more idiomatic, I think
This commit is contained in:
parent
07cec15696
commit
f07ac236bc
8 changed files with 193 additions and 109 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1 +1,3 @@
|
||||||
target/
|
target/
|
||||||
|
.idea
|
||||||
|
.cache
|
||||||
|
|
|
||||||
70
compile_commands.json
Normal file
70
compile_commands.json
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"arguments": [
|
||||||
|
"/usr/bin/clang++",
|
||||||
|
"-c",
|
||||||
|
"-std=c++17",
|
||||||
|
"-Wall",
|
||||||
|
"-Wextra",
|
||||||
|
"-pedantic",
|
||||||
|
"-Werror",
|
||||||
|
"-o",
|
||||||
|
"target/lox.cpp.o",
|
||||||
|
"src/lox.cpp"
|
||||||
|
],
|
||||||
|
"directory": "/Users/Shautvast/dev/clox",
|
||||||
|
"file": "/Users/Shautvast/dev/clox/src/lox.cpp",
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
]
|
||||||
6
makefile
6
makefile
|
|
@ -5,10 +5,10 @@ CC := clang++ -c -std=c++17 -Wall -Wextra -pedantic -Werror
|
||||||
SRCS := $(shell find $(SRC) -name '*.c')
|
SRCS := $(shell find $(SRC) -name '*.c')
|
||||||
OBJS := $(SRCS:%=$(TARGET)/%.o)
|
OBJS := $(SRCS:%=$(TARGET)/%.o)
|
||||||
|
|
||||||
$(TARGET)/lox: $(TARGET)/lox.cpp.o $(TARGET)/parser.cpp.o $(TARGET)/scanner.cpp.o
|
$(TARGET)/lox: $(TARGET)/lox.cpp.o $(TARGET)/parser.cpp.o $(TARGET)/scanner.cpp.o $(TARGET)/tokens.cpp.o
|
||||||
clang++ $(TARGET)/lox.cpp.o -L$(TARGET) -lscanner.cpp.o -o $(TARGET)/lox
|
clang++ $(TARGET)/lox.cpp.o -L$(TARGET) -lscanner.cpp.o -ltokens.cpp.o -o $(TARGET)/lox
|
||||||
|
|
||||||
$(TARGET)/utils.cpp.o: $(SRC)/utils.cpp
|
$(TARGET)/tokens.cpp.o: $(SRC)/tokens.cpp
|
||||||
$(CC) $< -o $@
|
$(CC) $< -o $@
|
||||||
|
|
||||||
$(TARGET)/scanner.cpp.o: $(SRC)/scanner.cpp
|
$(TARGET)/scanner.cpp.o: $(SRC)/scanner.cpp
|
||||||
|
|
|
||||||
|
|
@ -59,12 +59,7 @@ ScanResult run(std::string source) {
|
||||||
void print_tokens(std::list<Token> *list) {
|
void print_tokens(std::list<Token> *list) {
|
||||||
for (std::list<Token>::iterator token = list->begin(); token != list->end();
|
for (std::list<Token>::iterator token = list->begin(); token != list->end();
|
||||||
++token) {
|
++token) {
|
||||||
|
std::cout << token->to_string() << "(" << token->get_literal() << "), ";
|
||||||
if (token->literal != NULL) {
|
|
||||||
std::cout << token_name(token->type) << "(" << token->literal << "), ";
|
|
||||||
} else {
|
|
||||||
std::cout << token_name(token->type) << ", ";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "\n";
|
std::cout << "\n";
|
||||||
|
|
|
||||||
|
|
@ -22,23 +22,15 @@ ScanResult Scanner::scan_tokens() {
|
||||||
return scan_result;
|
return scan_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scanner::add_token(TokenType type) {
|
void Scanner::add_token(Token::Type type) {
|
||||||
Token token;
|
Token token =
|
||||||
token.type = type;
|
Token(type, source.substr(start, current_pos), "", current_line);
|
||||||
token.lexeme = source.substr(start, current_pos);
|
|
||||||
token.literal = NULL;
|
|
||||||
token.line = current_line;
|
|
||||||
|
|
||||||
token_list.push_front(token);
|
token_list.push_front(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scanner::add_token_with_literal(TokenType type, std::string literal) {
|
void Scanner::add_token_with_literal(Token::Type type, std::string literal) {
|
||||||
Token token;
|
Token token =
|
||||||
token.type = type;
|
Token(type, source.substr(start, current_pos), literal, current_line);
|
||||||
token.lexeme = source.substr(start, current_pos);
|
|
||||||
token.literal = static_cast<void *>(&literal);
|
|
||||||
token.line = current_line;
|
|
||||||
|
|
||||||
token_list.push_front(token);
|
token_list.push_front(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -52,40 +44,40 @@ void Scanner::scan_token() {
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '(':
|
case '(':
|
||||||
add_token(LEFT_PAREN);
|
add_token(Token::Type::LEFT_PAREN);
|
||||||
break;
|
break;
|
||||||
case ')':
|
case ')':
|
||||||
add_token(RIGHT_PAREN);
|
add_token(Token::Type::RIGHT_PAREN);
|
||||||
break;
|
break;
|
||||||
case '{':
|
case '{':
|
||||||
add_token(LEFT_BRACE);
|
add_token(Token::Type::LEFT_BRACE);
|
||||||
break;
|
break;
|
||||||
case '}':
|
case '}':
|
||||||
add_token(RIGHT_BRACE);
|
add_token(Token::Type::RIGHT_BRACE);
|
||||||
break;
|
break;
|
||||||
case ',':
|
case ',':
|
||||||
add_token(COMMA);
|
add_token(Token::Type::COMMA);
|
||||||
break;
|
break;
|
||||||
case '.':
|
case '.':
|
||||||
add_token(DOT);
|
add_token(Token::Type::DOT);
|
||||||
break;
|
break;
|
||||||
case '+':
|
case '+':
|
||||||
add_token(PLUS);
|
add_token(Token::Type::PLUS);
|
||||||
break;
|
break;
|
||||||
case '-':
|
case '-':
|
||||||
add_token(MINUS);
|
add_token(Token::Type::MINUS);
|
||||||
break;
|
break;
|
||||||
case '!':
|
case '!':
|
||||||
add_token(match('=') ? BANG_EQUAL : BANG);
|
add_token(match('=') ? Token::Type::BANG_EQUAL : Token::Type::BANG);
|
||||||
break;
|
break;
|
||||||
case '=':
|
case '=':
|
||||||
add_token(match('=') ? EQUAL_EQUAL : EQUAL);
|
add_token(match('=') ? Token::Type::EQUAL_EQUAL : Token::Type::EQUAL);
|
||||||
break;
|
break;
|
||||||
case '>':
|
case '>':
|
||||||
add_token(match('=') ? GREATER_EQUAL : GREATER);
|
add_token(match('=') ? Token::Type::GREATER_EQUAL : Token::Type::GREATER);
|
||||||
break;
|
break;
|
||||||
case '<':
|
case '<':
|
||||||
add_token(match('=') ? LESS_EQUAL : LESS);
|
add_token(match('=') ? Token::Type::LESS_EQUAL : Token::Type::LESS);
|
||||||
break;
|
break;
|
||||||
case '/':
|
case '/':
|
||||||
if (match('/')) {
|
if (match('/')) {
|
||||||
|
|
@ -93,7 +85,7 @@ void Scanner::scan_token() {
|
||||||
advance();
|
advance();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
add_token(SLASH);
|
add_token(Token::Type::SLASH);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ' ':
|
case ' ':
|
||||||
|
|
@ -125,9 +117,9 @@ void Scanner::identifier() {
|
||||||
|
|
||||||
std::string text = source.substr(start + 1, current_pos - start);
|
std::string text = source.substr(start + 1, current_pos - start);
|
||||||
|
|
||||||
const TokenType *tokentype = get_keyword_token(text);
|
const Token::Type *tokentype = get_keyword_token(text);
|
||||||
if (tokentype == NULL) {
|
if (tokentype == NULL) {
|
||||||
add_token(IDENTIFIER);
|
add_token(Token::Type::IDENTIFIER);
|
||||||
} else {
|
} else {
|
||||||
add_token(*tokentype);
|
add_token(*tokentype);
|
||||||
}
|
}
|
||||||
|
|
@ -140,7 +132,8 @@ void Scanner::number() {
|
||||||
advance();
|
advance();
|
||||||
while (is_digit(peek()))
|
while (is_digit(peek()))
|
||||||
advance();
|
advance();
|
||||||
add_token_with_literal(NUMBER, source.substr(start + 1, current_pos - start));
|
add_token_with_literal(Token::Type::NUMBER,
|
||||||
|
source.substr(start + 1, current_pos - start));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Scanner::is_digit(char c) { return c >= '0' && c <= '9'; }
|
bool Scanner::is_digit(char c) { return c >= '0' && c <= '9'; }
|
||||||
|
|
@ -159,8 +152,8 @@ void Scanner::string() {
|
||||||
|
|
||||||
advance();
|
advance();
|
||||||
|
|
||||||
std::string string = source.substr(start + 2, current_pos - start - 2);
|
std::string string = source.substr(start + 1, current_pos - start - 2);
|
||||||
add_token_with_literal(STRING, string);
|
add_token_with_literal(Token::Type::STRING, string);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Scanner::match(char expected) {
|
bool Scanner::match(char expected) {
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,8 @@ private:
|
||||||
public:
|
public:
|
||||||
Scanner(std::string s);
|
Scanner(std::string s);
|
||||||
ScanResult scan_tokens();
|
ScanResult scan_tokens();
|
||||||
void add_token(TokenType type);
|
void add_token(Token::Type type);
|
||||||
void add_token_with_literal(TokenType type, std::string literal);
|
void add_token_with_literal(Token::Type type, std::string literal);
|
||||||
char advance();
|
char advance();
|
||||||
void scan_token();
|
void scan_token();
|
||||||
void identifier();
|
void identifier();
|
||||||
|
|
@ -42,16 +42,20 @@ public:
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const std::string key;
|
const std::string key;
|
||||||
const TokenType value;
|
const Token::Type value;
|
||||||
} Item;
|
} Item;
|
||||||
|
|
||||||
static const Item keywords[] = {
|
static const Item keywords[] = {
|
||||||
{"and", AND}, {"class", CLASS}, {"else", ELSE}, {"false", FALSE},
|
{"and", Token::Type::AND}, {"class", Token::Type::CLASS},
|
||||||
{"for", FOR}, {"fun", FUN}, {"if", IF}, {"nil", NIL},
|
{"else", Token::Type::ELSE}, {"false", Token::Type::FALSE},
|
||||||
{"or", OR}, {"print", PRINT}, {"return", RETURN}, {"super", SUPER},
|
{"for", Token::Type::FOR}, {"fun", Token::Type::FUN},
|
||||||
{"this", THIS}, {"true", TRUE}, {"var", VAR}, {"while", WHILE}};
|
{"if", Token::Type::IF}, {"nil", Token::Type::NIL},
|
||||||
|
{"or", Token::Type::OR}, {"print", Token::Type::PRINT},
|
||||||
|
{"return", Token::Type::RETURN}, {"super", Token::Type::SUPER},
|
||||||
|
{"this", Token::Type::THIS}, {"true", Token::Type::TRUE},
|
||||||
|
{"var", Token::Type::VAR}, {"while", Token::Type::WHILE}};
|
||||||
|
|
||||||
inline static const TokenType *get_keyword_token(std::string key) {
|
inline static const Token::Type *get_keyword_token(std::string key) {
|
||||||
int low = 0;
|
int low = 0;
|
||||||
int high = sizeof(keywords) / sizeof(Item);
|
int high = sizeof(keywords) / sizeof(Item);
|
||||||
|
|
||||||
|
|
|
||||||
25
src/tokens.cpp
Normal file
25
src/tokens.cpp
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
#include "tokens.hpp"
|
||||||
|
|
||||||
|
Token::Token(Token::Type _tokentype, std::string _lexeme, std::string _literal,
|
||||||
|
int _line)
|
||||||
|
: lexeme(_lexeme), literal(_literal), line(_line), tokentype(_tokentype) {}
|
||||||
|
|
||||||
|
std::string Token::to_string() {
|
||||||
|
static const std::string tokens[] = {
|
||||||
|
"END_OF_FILE", "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"};
|
||||||
|
|
||||||
|
return tokens[(int)tokentype]; // TODO shift the enum int values
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Token::get_lexeme() { return lexeme; }
|
||||||
|
|
||||||
|
std::string Token::get_literal() { return literal; }
|
||||||
|
|
||||||
|
int Token::get_line() { return line; }
|
||||||
115
src/tokens.hpp
115
src/tokens.hpp
|
|
@ -2,65 +2,60 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
typedef enum {
|
class Token {
|
||||||
LEFT_PAREN,
|
private:
|
||||||
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
|
|
||||||
} TokenType;
|
|
||||||
|
|
||||||
static inline const char *token_name(TokenType type) {
|
|
||||||
static const char *tokens[] = {
|
|
||||||
"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"};
|
|
||||||
|
|
||||||
return tokens[type];
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
TokenType type;
|
|
||||||
std::string lexeme;
|
std::string lexeme;
|
||||||
void *literal;
|
std::string literal;
|
||||||
int line;
|
int line;
|
||||||
} Token;
|
|
||||||
|
public:
|
||||||
|
enum Type {
|
||||||
|
END_OF_FILE = 0,
|
||||||
|
LEFT_PAREN = 1,
|
||||||
|
RIGHT_PAREN = 2,
|
||||||
|
LEFT_BRACE = 3,
|
||||||
|
RIGHT_BRACE = 4,
|
||||||
|
COMMA = 5,
|
||||||
|
DOT = 6,
|
||||||
|
MINUS = 7,
|
||||||
|
PLUS = 8,
|
||||||
|
SEMICOLON = 9,
|
||||||
|
SLASH = 10,
|
||||||
|
STAR = 11,
|
||||||
|
BANG = 12,
|
||||||
|
BANG_EQUAL = 13,
|
||||||
|
EQUAL = 14,
|
||||||
|
EQUAL_EQUAL = 15,
|
||||||
|
GREATER = 16,
|
||||||
|
GREATER_EQUAL = 17,
|
||||||
|
LESS = 18,
|
||||||
|
LESS_EQUAL = 19,
|
||||||
|
IDENTIFIER = 20,
|
||||||
|
STRING = 21,
|
||||||
|
NUMBER = 22,
|
||||||
|
AND = 23,
|
||||||
|
CLASS = 24,
|
||||||
|
ELSE = 25,
|
||||||
|
FALSE = 26,
|
||||||
|
FUN = 27,
|
||||||
|
FOR = 28,
|
||||||
|
IF = 29,
|
||||||
|
NIL = 30,
|
||||||
|
OR = 31,
|
||||||
|
PRINT = 32,
|
||||||
|
RETURN = 33,
|
||||||
|
SUPER = 34,
|
||||||
|
THIS = 35,
|
||||||
|
TRUE = 36,
|
||||||
|
VAR = 37,
|
||||||
|
WHILE = 38,
|
||||||
|
} tokentype;
|
||||||
|
|
||||||
|
std::string get_lexeme();
|
||||||
|
std::string get_literal();
|
||||||
|
int get_line();
|
||||||
|
std::string to_string();
|
||||||
|
|
||||||
|
Token(Token::Type _tokentype, std::string _lexeme, std::string _literal,
|
||||||
|
int line);
|
||||||
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue