C++23, rusty error handling, renamed output repr of tokens
This commit is contained in:
parent
32e76fb704
commit
6fd95bd486
9 changed files with 144 additions and 130 deletions
|
|
@ -3,7 +3,7 @@
|
||||||
"arguments": [
|
"arguments": [
|
||||||
"/usr/bin/clang++",
|
"/usr/bin/clang++",
|
||||||
"-c",
|
"-c",
|
||||||
"-std=c++17",
|
"-std=c++23",
|
||||||
"-Wall",
|
"-Wall",
|
||||||
"-Wextra",
|
"-Wextra",
|
||||||
"-pedantic",
|
"-pedantic",
|
||||||
|
|
@ -15,56 +15,5 @@
|
||||||
"directory": "/Users/Shautvast/dev/clox",
|
"directory": "/Users/Shautvast/dev/clox",
|
||||||
"file": "/Users/Shautvast/dev/clox/src/lox.cpp",
|
"file": "/Users/Shautvast/dev/clox/src/lox.cpp",
|
||||||
"output": "/Users/Shautvast/dev/clox/target/lox.cpp.o"
|
"output": "/Users/Shautvast/dev/clox/target/lox.cpp.o"
|
||||||
},
|
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/usr/bin/clang++",
|
|
||||||
"-c",
|
|
||||||
"-std=c++17",
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-pedantic",
|
|
||||||
"-Werror",
|
|
||||||
"-o",
|
|
||||||
"target/parser.cpp.o",
|
|
||||||
"src/parser.cpp"
|
|
||||||
],
|
|
||||||
"directory": "/Users/Shautvast/dev/clox",
|
|
||||||
"file": "/Users/Shautvast/dev/clox/src/parser.cpp",
|
|
||||||
"output": "/Users/Shautvast/dev/clox/target/parser.cpp.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/usr/bin/clang++",
|
|
||||||
"-c",
|
|
||||||
"-std=c++17",
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-pedantic",
|
|
||||||
"-Werror",
|
|
||||||
"-o",
|
|
||||||
"target/scanner.cpp.o",
|
|
||||||
"src/scanner.cpp"
|
|
||||||
],
|
|
||||||
"directory": "/Users/Shautvast/dev/clox",
|
|
||||||
"file": "/Users/Shautvast/dev/clox/src/scanner.cpp",
|
|
||||||
"output": "/Users/Shautvast/dev/clox/target/scanner.cpp.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/usr/bin/clang++",
|
|
||||||
"-c",
|
|
||||||
"-std=c++17",
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-pedantic",
|
|
||||||
"-Werror",
|
|
||||||
"-o",
|
|
||||||
"target/tokens.cpp.o",
|
|
||||||
"src/tokens.cpp"
|
|
||||||
],
|
|
||||||
"directory": "/Users/Shautvast/dev/clox",
|
|
||||||
"file": "/Users/Shautvast/dev/clox/src/tokens.cpp",
|
|
||||||
"output": "/Users/Shautvast/dev/clox/target/tokens.cpp.o"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
2
makefile
2
makefile
|
|
@ -1,6 +1,6 @@
|
||||||
TARGET := ./target
|
TARGET := ./target
|
||||||
SRC := ./src
|
SRC := ./src
|
||||||
CC := clang++ -c -std=c++17 -Wall -Wextra -pedantic -Werror
|
CC := clang++ -c -std=c++23 -Wall -Wextra -pedantic -Werror
|
||||||
|
|
||||||
SRCS := $(shell find $(SRC) -name '*.c')
|
SRCS := $(shell find $(SRC) -name '*.c')
|
||||||
OBJS := $(SRCS:%=$(TARGET)/%.o)
|
OBJS := $(SRCS:%=$(TARGET)/%.o)
|
||||||
|
|
|
||||||
31
src/error.hpp
Normal file
31
src/error.hpp
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
class Error {
|
||||||
|
|
||||||
|
public:
|
||||||
|
string message;
|
||||||
|
Error(string _message) : message(_message){};
|
||||||
|
};
|
||||||
|
|
||||||
|
class Void {};
|
||||||
|
|
||||||
|
template <typename R> using Result = std::variant<R, Error>;
|
||||||
|
|
||||||
|
template <typename R> bool is_err(Result<R> r) {
|
||||||
|
return std::holds_alternative<Error>(r);
|
||||||
|
}
|
||||||
|
template <typename R> bool is_ok(Result<R> r) {
|
||||||
|
return std::holds_alternative<R>(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename R> R Ok(Result<R> r) { return std::get<R>(r); }
|
||||||
|
/// enables rewrapping errors in a new Result type
|
||||||
|
template <typename R> Error Err(Result<R> r) { return std::get<Error>(r); }
|
||||||
|
template <typename R> string err_msg(Result<R> r) {
|
||||||
|
return std::get<Error>(r).message;
|
||||||
|
}
|
||||||
21
src/lox.cpp
21
src/lox.cpp
|
|
@ -12,7 +12,7 @@ using namespace std;
|
||||||
void print_tokens(vector<Token> *list);
|
void print_tokens(vector<Token> *list);
|
||||||
int run_file(string file);
|
int run_file(string file);
|
||||||
void run_prompt(void);
|
void run_prompt(void);
|
||||||
ScanResult run(string source);
|
Result<vector<Token>> run(string source);
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
if (argc > 2) {
|
if (argc > 2) {
|
||||||
|
|
@ -36,7 +36,7 @@ int run_file(string filename) {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ScanResult scan_result = run(content);
|
Result<vector<Token>> scan_result = run(content);
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
@ -49,17 +49,22 @@ void run_prompt(void) {
|
||||||
|
|
||||||
getline(cin, line);
|
getline(cin, line);
|
||||||
|
|
||||||
ScanResult scan_result = run(line.substr(0, line.length()));
|
auto scan_result = run(line.substr(0, line.length()));
|
||||||
// print_tokens(&scan_result.token_list);
|
// print_tokens(&scan_result.token_list);
|
||||||
if (!scan_result.had_error) {
|
if (is_ok(scan_result)) {
|
||||||
Expression *e = (new Parser())->parse(scan_result.token_list);
|
auto expression = (new Parser())->parse(get<vector<Token>>(scan_result));
|
||||||
cout << e->as_string();
|
if (is_ok(expression)) {
|
||||||
cout << "\n";
|
cout << Ok(expression)->as_string() << "\n";
|
||||||
|
} else {
|
||||||
|
cout << err_msg(expression) << "\n";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cout << err_msg(scan_result) << "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ScanResult run(string source) {
|
Result<vector<Token>> run(string source) {
|
||||||
Scanner *scanner = new Scanner(source);
|
Scanner *scanner = new Scanner(source);
|
||||||
return scanner->scan_tokens();
|
return scanner->scan_tokens();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#include "parser.hpp"
|
#include "parser.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
|
@ -61,7 +62,7 @@ string Literal::as_string() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// class Parser
|
// class Parser
|
||||||
Expression *Parser::parse(vector<Token> tokenlist) {
|
Result<Expression *> Parser::parse(vector<Token> tokenlist) {
|
||||||
tokens = tokenlist;
|
tokens = tokenlist;
|
||||||
current_token = 0;
|
current_token = 0;
|
||||||
return expression();
|
return expression();
|
||||||
|
|
@ -101,25 +102,25 @@ bool Parser::match(int count, ...) {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
Token *Parser::consume(Token::Type typ, string message) {
|
Result<Token *> Parser::consume(Token::Type typ, string message) {
|
||||||
if (check(typ)) {
|
if (check(typ)) {
|
||||||
return advance();
|
return advance();
|
||||||
}
|
}
|
||||||
throw error(peek(), message);
|
return error(peek(), message);
|
||||||
}
|
}
|
||||||
|
|
||||||
runtime_error Parser::error(Token token, string message) {
|
Error Parser::error(Token token, string message) {
|
||||||
std::cout << token.as_string() << " " << message;
|
std::cout << token.as_string() << " " << message;
|
||||||
return runtime_error(message); // TODO no exceptions
|
return Error(message); // TODO no exceptions
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression *Parser::primary() {
|
Result<Expression *> Parser::primary() {
|
||||||
if (match(1, Token::Type::FALSE))
|
if (match(1, Token::Type::FALSE))
|
||||||
return new Literal(false);
|
return new Literal(false);
|
||||||
if (match(1, Token::Type::TRUE))
|
if (match(1, Token::Type::TRUE))
|
||||||
return new Literal(true);
|
return new Literal(true);
|
||||||
if (match(1, Token::Type::NIL))
|
if (match(1, Token::Type::NIL))
|
||||||
return new Literal(new Void());
|
return new Literal(new NilType());
|
||||||
if (match(1, Token::Type::NUMBER)) {
|
if (match(1, Token::Type::NUMBER)) {
|
||||||
return new Literal(stod(previous()->literal));
|
return new Literal(stod(previous()->literal));
|
||||||
}
|
}
|
||||||
|
|
@ -127,62 +128,90 @@ Expression *Parser::primary() {
|
||||||
return new Literal(previous()->literal);
|
return new Literal(previous()->literal);
|
||||||
}
|
}
|
||||||
if (match(1, Token::Type::LEFT_PAREN)) {
|
if (match(1, Token::Type::LEFT_PAREN)) {
|
||||||
Expression *expr = expression();
|
auto expr = expression();
|
||||||
consume(Token::Type::RIGHT_PAREN, "Expect ')'.");
|
Result<Token *> r = consume(Token::Type::RIGHT_PAREN, "Expect ')'.");
|
||||||
return new Grouping(expr);
|
if (is_err(r)) {
|
||||||
|
return Err(r);
|
||||||
|
}
|
||||||
|
return new Grouping(Ok(expr));
|
||||||
}
|
}
|
||||||
throw runtime_error("Expected an expression");
|
return Error("Expected an expression");
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression *Parser::unary() {
|
Result<Expression *> Parser::unary() {
|
||||||
if (match(2, Token::BANG, Token::Type::MINUS)) {
|
if (match(2, Token::BANG, Token::Type::MINUS)) {
|
||||||
Token *op = previous();
|
Token *op = previous();
|
||||||
Expression *right = unary();
|
Result<Expression *> right = unary();
|
||||||
return new Unary(op, right);
|
if (is_ok(right)) {
|
||||||
|
return new Unary(op, Ok(right));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return primary();
|
return primary();
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression *Parser::expression() { return equality(); }
|
Result<Expression *> Parser::expression() { return equality(); }
|
||||||
|
|
||||||
Expression *Parser::factor() {
|
Result<Expression *> Parser::factor() {
|
||||||
Expression *expr = unary();
|
Result<Expression *> expr = unary();
|
||||||
|
if (is_err(expr)) {
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
while (match(2, Token::Type::SLASH, Token::Type::STAR)) {
|
while (match(2, Token::Type::SLASH, Token::Type::STAR)) {
|
||||||
Token *op = previous();
|
Token *op = previous();
|
||||||
Expression *right = unary();
|
auto right = unary();
|
||||||
expr = new Binary(expr, op, right);
|
if (is_err(right)) {
|
||||||
|
return right;
|
||||||
|
}
|
||||||
|
expr = new Binary(Ok(expr), op, Ok(right));
|
||||||
}
|
}
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression *Parser::term() {
|
Result<Expression *> Parser::term() {
|
||||||
Expression *expr = factor();
|
auto expr = factor();
|
||||||
|
if (is_err(expr)) {
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
while (match(2, Token::Type::MINUS, Token::Type::PLUS)) {
|
while (match(2, Token::Type::MINUS, Token::Type::PLUS)) {
|
||||||
Token *op = previous();
|
Token *op = previous();
|
||||||
Expression *right = factor();
|
auto right = factor();
|
||||||
expr = new Binary(expr, op, right);
|
if (is_err(right)) {
|
||||||
|
return right;
|
||||||
|
}
|
||||||
|
expr = new Binary(Ok(expr), op, Ok(right));
|
||||||
}
|
}
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression *Parser::equality(void) {
|
Result<Expression *> Parser::equality(void) {
|
||||||
Expression *expr = comparison();
|
auto expr = comparison();
|
||||||
|
if (is_err(expr)) {
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
while (match(2, Token::Type::BANG_EQUAL, Token::Type::BANG_EQUAL)) {
|
while (match(2, Token::Type::BANG_EQUAL, Token::Type::BANG_EQUAL)) {
|
||||||
Token *op = previous();
|
Token *op = previous();
|
||||||
Expression *right = comparison();
|
auto right = comparison();
|
||||||
return new Binary(expr, op, right);
|
if (is_err(right)) {
|
||||||
|
return right;
|
||||||
|
}
|
||||||
|
return new Binary(Ok(expr), op, Ok(right));
|
||||||
}
|
}
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression *Parser::comparison(void) {
|
Result<Expression *> Parser::comparison(void) {
|
||||||
Expression *expr = term();
|
auto expr = term();
|
||||||
|
if (is_err(expr)) {
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
while (match(4, Token::Type::GREATER, Token::Type::GREATER_EQUAL,
|
while (match(4, Token::Type::GREATER, Token::Type::GREATER_EQUAL,
|
||||||
Token::Type::LESS, Token::Type::LESS_EQUAL)) {
|
Token::Type::LESS, Token::Type::LESS_EQUAL)) {
|
||||||
Token *op = previous();
|
Token *op = previous();
|
||||||
Expression *right = term();
|
auto right = term();
|
||||||
expr = new Binary(expr, op, right);
|
if (is_err(right)) {
|
||||||
|
return right;
|
||||||
|
}
|
||||||
|
expr = new Binary(Ok(expr), op, Ok(right));
|
||||||
}
|
}
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "error.hpp"
|
||||||
#include "tokens.hpp"
|
#include "tokens.hpp"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
@ -53,7 +54,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
/// empty class that is the type of the Nil value
|
/// empty class that is the type of the Nil value
|
||||||
class Void {};
|
class NilType {};
|
||||||
|
|
||||||
/// encapsulates a value: numeric, string etc
|
/// encapsulates a value: numeric, string etc
|
||||||
class Literal : public Expression {
|
class Literal : public Expression {
|
||||||
|
|
@ -66,16 +67,16 @@ public:
|
||||||
double_t numeric;
|
double_t numeric;
|
||||||
bool boolean;
|
bool boolean;
|
||||||
string str;
|
string str;
|
||||||
Void dummy;
|
NilType dummy;
|
||||||
|
|
||||||
Value(double_t _numeric) : numeric(_numeric) {}
|
Value(double_t _numeric) : numeric(_numeric) {}
|
||||||
Value(bool _boolean) : boolean(_boolean) {}
|
Value(bool _boolean) : boolean(_boolean) {}
|
||||||
Value(string _str) : str(_str) {}
|
Value(string _str) : str(_str) {}
|
||||||
Value(Void v) : dummy(v) {}
|
Value(NilType v) : dummy(v) {}
|
||||||
~Value() {}
|
~Value() {}
|
||||||
} value;
|
} value;
|
||||||
|
|
||||||
Literal(Void v) : valuetype(ValueType::Nil), value(v){};
|
Literal(NilType v) : valuetype(ValueType::Nil), value(v){};
|
||||||
Literal(double_t _numeric) : valuetype(ValueType::Numeric), value(_numeric){};
|
Literal(double_t _numeric) : valuetype(ValueType::Numeric), value(_numeric){};
|
||||||
Literal(string _str) : valuetype(ValueType::String), value(_str){};
|
Literal(string _str) : valuetype(ValueType::String), value(_str){};
|
||||||
Literal(bool _boolean) : valuetype(ValueType::Boolean), value(_boolean){};
|
Literal(bool _boolean) : valuetype(ValueType::Boolean), value(_boolean){};
|
||||||
|
|
@ -106,26 +107,26 @@ class Parser {
|
||||||
/// checks if the current token is of the specified type and
|
/// checks if the current token is of the specified type and
|
||||||
/// moves the token forward if so, otherwise throws an exception with
|
/// moves the token forward if so, otherwise throws an exception with
|
||||||
/// the specified message
|
/// the specified message
|
||||||
Token *consume(Token::Type typ, string message);
|
Result<Token *> consume(Token::Type typ, string message);
|
||||||
/// throws an exception for the specified token with the specified message
|
/// throws an exception for the specified token with the specified message
|
||||||
runtime_error error(Token token, string message);
|
Error error(Token token, string message);
|
||||||
/// tries to parse the token as a primary value (string, number etc)
|
/// tries to parse the token as a primary value (string, number etc)
|
||||||
Expression *primary();
|
Result<Expression *> primary();
|
||||||
/// tries to parse the tokens as a unary expression
|
/// tries to parse the tokens as a unary expression
|
||||||
Expression *unary();
|
Result<Expression *> unary();
|
||||||
/// tries to parse the tokens
|
/// tries to parse the tokens
|
||||||
Expression *expression();
|
Result<Expression *> expression();
|
||||||
/// tries to parse the tokens as a multiplication or division
|
/// tries to parse the tokens as a multiplication or division
|
||||||
Expression *factor();
|
Result<Expression *> factor();
|
||||||
/// tries to parse the tokens as an addition or subtraction
|
/// tries to parse the tokens as an addition or subtraction
|
||||||
Expression *term();
|
Result<Expression *> term();
|
||||||
/// tries to parse the tokens as an equality (`a == b` / `a!= b`)
|
/// tries to parse the tokens as an equality (`a == b` / `a!= b`)
|
||||||
Expression *equality(void);
|
Result<Expression *> equality();
|
||||||
/// tries to parse the tokens as a comparison (`a > b` / `a >= b` / `a < b` /
|
/// tries to parse the tokens as a comparison (`a > b` / `a >= b` / `a < b` /
|
||||||
/// `a <= b` )
|
/// `a <= b` )
|
||||||
Expression *comparison(void);
|
Result<Expression *> comparison();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// public method for parsing expressions
|
/// public method for parsing expressions
|
||||||
Expression *parse(vector<Token> tokenlist);
|
Result<Expression *> parse(vector<Token> tokenlist);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#include "scanner.hpp"
|
#include "scanner.hpp"
|
||||||
|
#include "error.hpp"
|
||||||
#include "tokens.hpp"
|
#include "tokens.hpp"
|
||||||
#include <cstdbool>
|
#include <cstdbool>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
@ -23,17 +24,15 @@ Scanner::Scanner(string _source)
|
||||||
: had_error(false), current_pos(0), start(0), current_line(1),
|
: had_error(false), current_pos(0), start(0), current_line(1),
|
||||||
source(_source), token_list(vector<Token>()) {}
|
source(_source), token_list(vector<Token>()) {}
|
||||||
|
|
||||||
ScanResult Scanner::scan_tokens() {
|
Result<vector<Token>> Scanner::scan_tokens() {
|
||||||
while (current_pos < source.length()) {
|
while (current_pos < source.length()) {
|
||||||
start = current_pos;
|
start = current_pos;
|
||||||
scan_token();
|
Result<Void> r = scan_token();
|
||||||
|
if (is_err(r)) {
|
||||||
|
return Err(r);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return token_list;
|
||||||
ScanResult scan_result;
|
|
||||||
scan_result.token_list = token_list;
|
|
||||||
scan_result.had_error = had_error;
|
|
||||||
|
|
||||||
return scan_result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scanner::add_token(Token::Type type) {
|
void Scanner::add_token(Token::Type type) {
|
||||||
|
|
@ -51,7 +50,7 @@ char Scanner::advance() {
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scanner::scan_token() {
|
Result<Void> Scanner::scan_token() {
|
||||||
char c = advance();
|
char c = advance();
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
|
@ -119,10 +118,11 @@ void Scanner::scan_token() {
|
||||||
} else if (is_alpha(c)) {
|
} else if (is_alpha(c)) {
|
||||||
identifier();
|
identifier();
|
||||||
} else {
|
} else {
|
||||||
error("Unexpected character.");
|
return Error{"Unexpected character."};
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
return Void{};
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scanner::identifier() {
|
void Scanner::identifier() {
|
||||||
|
|
@ -159,7 +159,7 @@ void Scanner::scan_string() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_at_end()) {
|
if (is_at_end()) {
|
||||||
error("Unterminated string.");
|
report("Unterminated string.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -202,7 +202,7 @@ bool Scanner::is_alphanumeric(char c) { return is_alpha(c) || is_digit(c); }
|
||||||
|
|
||||||
bool Scanner::is_at_end(void) { return current_pos >= source.length(); }
|
bool Scanner::is_at_end(void) { return current_pos >= source.length(); }
|
||||||
|
|
||||||
void Scanner::error(string message) { report("", message); }
|
void Scanner::report(string message) { report("", message); }
|
||||||
|
|
||||||
void Scanner::report(string where, std::string message) {
|
void Scanner::report(string where, std::string message) {
|
||||||
cout << "*[Line " << current_line << "] Error " << where << " : " << message
|
cout << "*[Line " << current_line << "] Error " << where << " : " << message
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "error.hpp"
|
||||||
#include "tokens.hpp"
|
#include "tokens.hpp"
|
||||||
#include <cstdbool>
|
#include <cstdbool>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
@ -23,11 +24,11 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Scanner(string s);
|
Scanner(string s);
|
||||||
ScanResult scan_tokens();
|
Result<vector<Token>> scan_tokens();
|
||||||
|
Result<Void> scan_token();
|
||||||
void add_token(Token::Type type);
|
void add_token(Token::Type type);
|
||||||
void add_token(Token::Type type, string literal);
|
void add_token(Token::Type type, string literal);
|
||||||
char advance();
|
char advance();
|
||||||
void scan_token();
|
|
||||||
void identifier();
|
void identifier();
|
||||||
void number();
|
void number();
|
||||||
bool is_digit(char c);
|
bool is_digit(char c);
|
||||||
|
|
@ -38,6 +39,6 @@ public:
|
||||||
bool is_alpha(char c);
|
bool is_alpha(char c);
|
||||||
bool is_alphanumeric(char c);
|
bool is_alphanumeric(char c);
|
||||||
bool is_at_end(void);
|
bool is_at_end(void);
|
||||||
void error(string message);
|
void report(string message);
|
||||||
void report(string where, string message);
|
void report(string where, string message);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -7,14 +7,12 @@ Token::Token(Token::Type _tokentype, string _lexeme, string _literal, int _line)
|
||||||
|
|
||||||
string token_name(Token::Type tokentype) {
|
string token_name(Token::Type tokentype) {
|
||||||
static const std::string tokens[] = {
|
static const std::string tokens[] = {
|
||||||
"END_OF_FILE", "LEFT_PAREN", "RIGHT_PAREN", "LEFT_BRACE", "RIGHT_BRACE",
|
"EOF", "(", ")", "{", "}", ",", "*",
|
||||||
"COMMA", "DOT", "MINUS", "PLUS", "SEMICOLON",
|
"-", "+", ";", "/", "*", "!", "!=",
|
||||||
"SLASH", "STAR", "BANG", "BANG_EQUAL", "EQUAL",
|
"=", "==", ">", ">=", "<", "<=", "IDENTIFIER",
|
||||||
"EQUAL_EQUAL", "GREATER", "GREATER_EQUAL", "LESS", "LESS_EQUAL",
|
"string", "number", "and", "class", "else", "false", "fun",
|
||||||
"IDENTIFIER", "STRING", "NUMBER", "AND", "CLASS",
|
"for", "if", "Nil", "or", "print", "return", "super",
|
||||||
"ELSE", "FALSE", "FUN", "FOR", "IF",
|
"this", "true", "var", "while"};
|
||||||
"NIL", "OR", "PRINT", "RETURN", "SUPER",
|
|
||||||
"THIS", "TRUE", "VAR", "WHILE"};
|
|
||||||
return tokens[(int)tokentype];
|
return tokens[(int)tokentype];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue