initial commit
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
build
|
||||||
|
cmake-build-debug
|
||||||
3
.idea/.gitignore
generated
vendored
Normal file
3
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
4
.idea/misc.xml
generated
Normal file
4
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
||||||
|
</project>
|
||||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/msql.iml" filepath="$PROJECT_DIR$/.idea/msql.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
2
.idea/msql.iml
generated
Normal file
2
.idea/msql.iml
generated
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module classpath="CMake" type="CPP_MODULE" version="4" />
|
||||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
30
.vscode/c_cpp_properties.json
vendored
Normal file
30
.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Mac",
|
||||||
|
"browse": {
|
||||||
|
"path": [
|
||||||
|
"${workspaceFolder}"
|
||||||
|
],
|
||||||
|
"limitSymbolsToIncludedHeaders": true
|
||||||
|
},
|
||||||
|
"includePath": [
|
||||||
|
"${workspaceFolder}/**",
|
||||||
|
"${workspaceFolder}/stdlib",
|
||||||
|
"/usr/local/opt/openssl/include",
|
||||||
|
"${workspaceFolder}"
|
||||||
|
],
|
||||||
|
"defines": [],
|
||||||
|
"macFrameworkPath": [
|
||||||
|
"/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/System/Library/Frameworks"
|
||||||
|
],
|
||||||
|
"compilerPath": "/usr/bin/clang",
|
||||||
|
"cStandard": "c11",
|
||||||
|
"cppStandard": "c++17",
|
||||||
|
"intelliSenseMode": "clang-x64",
|
||||||
|
"configurationProvider": "vector-of-bool.cmake-tools",
|
||||||
|
"compileCommands": "${workspaceFolder}/build/compile_commands.json"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version": 4
|
||||||
|
}
|
||||||
20
.vscode/launch.json
vendored
Normal file
20
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "(lldb) Launch",
|
||||||
|
"type": "cppdbg",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/build/msql",
|
||||||
|
"args": [],
|
||||||
|
"stopAtEntry": false,
|
||||||
|
"cwd": "${fileDirname}",
|
||||||
|
"environment": [],
|
||||||
|
"externalConsole": false,
|
||||||
|
"MIMode": "lldb"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
78
.vscode/settings.json
vendored
Normal file
78
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
{
|
||||||
|
"files.associations": {
|
||||||
|
"regex": "cpp",
|
||||||
|
"__config": "cpp",
|
||||||
|
"__nullptr": "cpp",
|
||||||
|
"exception": "cpp",
|
||||||
|
"initializer_list": "cpp",
|
||||||
|
"new": "cpp",
|
||||||
|
"stdexcept": "cpp",
|
||||||
|
"typeinfo": "cpp",
|
||||||
|
"__functional_03": "cpp",
|
||||||
|
"__string": "cpp",
|
||||||
|
"deque": "cpp",
|
||||||
|
"functional": "cpp",
|
||||||
|
"string": "cpp",
|
||||||
|
"system_error": "cpp",
|
||||||
|
"vector": "cpp",
|
||||||
|
"__bit_reference": "cpp",
|
||||||
|
"__functional_base": "cpp",
|
||||||
|
"algorithm": "cpp",
|
||||||
|
"atomic": "cpp",
|
||||||
|
"bitset": "cpp",
|
||||||
|
"chrono": "cpp",
|
||||||
|
"iterator": "cpp",
|
||||||
|
"limits": "cpp",
|
||||||
|
"locale": "cpp",
|
||||||
|
"memory": "cpp",
|
||||||
|
"ratio": "cpp",
|
||||||
|
"tuple": "cpp",
|
||||||
|
"type_traits": "cpp",
|
||||||
|
"unordered_map": "cpp",
|
||||||
|
"__functional_base_03": "cpp",
|
||||||
|
"__hash_table": "cpp",
|
||||||
|
"__tuple": "cpp",
|
||||||
|
"utility": "cpp",
|
||||||
|
"__split_buffer": "cpp",
|
||||||
|
"ios": "cpp",
|
||||||
|
"string_view": "cpp",
|
||||||
|
"map": "cpp",
|
||||||
|
"__tree": "cpp",
|
||||||
|
"istream": "cpp",
|
||||||
|
"__locale": "cpp",
|
||||||
|
"iosfwd": "cpp",
|
||||||
|
"array": "cpp",
|
||||||
|
"hash_map": "cpp",
|
||||||
|
"list": "cpp",
|
||||||
|
"optional": "cpp",
|
||||||
|
"sstream": "cpp",
|
||||||
|
"cstddef": "cpp",
|
||||||
|
"hashtable": "cpp",
|
||||||
|
"variant": "cpp",
|
||||||
|
"__debug": "cpp",
|
||||||
|
"__errc": "cpp",
|
||||||
|
"__mutex_base": "cpp",
|
||||||
|
"__node_handle": "cpp",
|
||||||
|
"__threading_support": "cpp",
|
||||||
|
"cctype": "cpp",
|
||||||
|
"cmath": "cpp",
|
||||||
|
"cstdarg": "cpp",
|
||||||
|
"cstdint": "cpp",
|
||||||
|
"cstdio": "cpp",
|
||||||
|
"cstdlib": "cpp",
|
||||||
|
"cstring": "cpp",
|
||||||
|
"ctime": "cpp",
|
||||||
|
"cwchar": "cpp",
|
||||||
|
"cwctype": "cpp",
|
||||||
|
"fstream": "cpp",
|
||||||
|
"iomanip": "cpp",
|
||||||
|
"iostream": "cpp",
|
||||||
|
"mutex": "cpp",
|
||||||
|
"ostream": "cpp",
|
||||||
|
"streambuf": "cpp",
|
||||||
|
"thread": "cpp"
|
||||||
|
},
|
||||||
|
"C_Cpp.intelliSenseEngineFallback": "Disabled",
|
||||||
|
"cmake.configureOnOpen": true,
|
||||||
|
"C_Cpp.configurationWarnings": "Disabled"
|
||||||
|
}
|
||||||
26
.vscode/tasks.json
vendored
Normal file
26
.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||||
|
// for the documentation about the tasks.json format
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "compile",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "clang++ -o mi -g -mmacosx-version-min=10.14 -lstdc++ -std=c++1z -lssl -lcrypto -lpqxx -lpq -L/usr/local/opt/openssl/lib -I/usr/local/opt/openssl/include -L/usr/local/opt/libpqxx/lib -I/usr/local/opt/libpqxx/include -L/usr/local/opt/postgres/lib -I/usr/local/opt/postgres/include -I./ -I./stdlib *.cpp ./stdlib/*.cpp",
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "compile O3",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "clang++ -o mi -O3 -mmacosx-version-min=10.14 -lstdc++ -std=c++1z -lssl -lcrypto -lpqxx -lpq -L/usr/local/opt/openssl/lib -I/usr/local/opt/openssl/include -L/usr/local/opt/libpqxx/lib -I/usr/local/opt/libpqxx/include -L/usr/local/opt/postgres/lib -I/usr/local/opt/postgres/include -I./ -I./stdlib *.cpp ./stdlib/*.cpp",
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": false
|
||||||
|
},
|
||||||
|
"problemMatcher": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
21
CMakeLists.txt
Normal file
21
CMakeLists.txt
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.0)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||||
|
|
||||||
|
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14")
|
||||||
|
|
||||||
|
|
||||||
|
project(msql)
|
||||||
|
|
||||||
|
set(PROJECT_NAME msql)
|
||||||
|
|
||||||
|
set(SOURCE
|
||||||
|
exception.cpp lexer.cpp parser.cpp executor.cpp main.cpp)
|
||||||
|
|
||||||
|
add_executable(${PROJECT_NAME} ${SOURCE})
|
||||||
|
|
||||||
|
target_link_libraries(${PROJECT_NAME} stdc++ m)
|
||||||
|
|
||||||
|
target_compile_options(msql PRIVATE -g)
|
||||||
9
exception.cpp
Normal file
9
exception.cpp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#include "exception.h"
|
||||||
|
|
||||||
|
|
||||||
|
Exception::Exception(const std::string &msg) {
|
||||||
|
cause = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char* Exception::what() const noexcept { return cause.c_str(); }
|
||||||
15
exception.h
Normal file
15
exception.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "lexer.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class Exception : public std::exception {
|
||||||
|
private:
|
||||||
|
std::string cause;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Exception(const std::string &msg);
|
||||||
|
|
||||||
|
const char* what() const noexcept;
|
||||||
|
};
|
||||||
29
executor.cpp
Normal file
29
executor.cpp
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#include "executor.h"
|
||||||
|
#include "exception.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Executor::Executor() {
|
||||||
|
// TODO init database
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Executor::execute(Node& node) {
|
||||||
|
switch (node.node_type) {
|
||||||
|
case NodeType::create_table:
|
||||||
|
return execute_create_table(static_cast<CreateTableNode &>(node));
|
||||||
|
case NodeType::select_from:
|
||||||
|
return execute_select(node);
|
||||||
|
default:
|
||||||
|
// TODO error message
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Executor::execute_create_table(CreateTableNode& node) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Executor::execute_select(Node& node) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
21
executor.h
Normal file
21
executor.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class Executor {
|
||||||
|
private:
|
||||||
|
|
||||||
|
public:
|
||||||
|
Executor();
|
||||||
|
|
||||||
|
bool execute(Node& node);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool execute_create_table(CreateTableNode& node);
|
||||||
|
bool execute_select(Node& node);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
};
|
||||||
376
lexer.cpp
Normal file
376
lexer.cpp
Normal file
@@ -0,0 +1,376 @@
|
|||||||
|
#include "lexer.h"
|
||||||
|
#include "exception.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
|
||||||
|
Token::Token(const std::string &token_str, TokenType typ) {
|
||||||
|
token_string = token_str;
|
||||||
|
type = typ;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lexer::parse(const std::string &code) {
|
||||||
|
// TODO handle empty code
|
||||||
|
tokens.clear();
|
||||||
|
|
||||||
|
// PERF something like this to prealocate ??
|
||||||
|
if (code.size() > 100) {
|
||||||
|
tokens.reserve(code.size() / 10);
|
||||||
|
}
|
||||||
|
code_str = code;
|
||||||
|
if (!code_str.empty() && code_str.back() != '\n') {
|
||||||
|
code_str.append("\n"); // TODO tempo solution to prevent possible situation when last line is a comment
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO make it constant
|
||||||
|
std::regex words_regex("[0-9]+\\.[0-9]+|[0-9][0-9_]+[0-9]|[0-9]+|[A-Za-z]+[A-Za-z0-9_#]*|[\\(\\)\\[\\]\\{\\}]|[-\\+\\*/"
|
||||||
|
",;:\?]|==|>=|<=|~=|>|<|=|;|~|\\|\\||&&|\n|\r|\r\n|'([^']|'')*'|\".*?\"|%.*?\n");
|
||||||
|
|
||||||
|
auto words_begin = std::sregex_iterator(code_str.begin(), code_str.end(), words_regex);
|
||||||
|
auto words_end = std::sregex_iterator();
|
||||||
|
|
||||||
|
for (std::sregex_iterator i = words_begin; i != words_end; ++i) {
|
||||||
|
std::smatch match = *i;
|
||||||
|
std::string match_str = match.str();
|
||||||
|
TokenType token_type = type(match_str);
|
||||||
|
if (token_type == TokenType::string_literal) {
|
||||||
|
match_str = stringLiteral(match_str);
|
||||||
|
} else {
|
||||||
|
tokens.push_back(Token{match_str, token_type});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEBUG IT
|
||||||
|
// debugTokens();
|
||||||
|
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lexer::debugTokens() {
|
||||||
|
int i = 0;
|
||||||
|
for (std::vector<Token>::iterator it = tokens.begin(); it != tokens.end(); ++it) {
|
||||||
|
std::cerr << i << "\t" << it->token_string << std::endl;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Token Lexer::currentToken() { return tokens[index]; }
|
||||||
|
|
||||||
|
void Lexer::nextToken() {
|
||||||
|
if (index < tokens.size()) {
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lexer::skipToken(TokenType type) {
|
||||||
|
if (tokenType() == type) {
|
||||||
|
nextToken();
|
||||||
|
} else {
|
||||||
|
throw Exception("ERROR unexpected token " + currentToken().token_string + ", instead of " + typeToString(type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lexer::skipTokenOptional(TokenType type) {
|
||||||
|
if (tokenType() == type) {
|
||||||
|
nextToken();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TokenType Lexer::tokenType() { return index < tokens.size() ? currentToken().type : TokenType::eof; }
|
||||||
|
|
||||||
|
TokenType Lexer::nextTokenType() { return index < tokens.size() - 1 ? tokens[index + 1].type : TokenType::eof; }
|
||||||
|
|
||||||
|
TokenType Lexer::prevTokenType() { return index > 0 ? tokens[index - 1].type : TokenType::undef; }
|
||||||
|
|
||||||
|
bool Lexer::isRelationalOperator(TokenType token_type) {
|
||||||
|
return (token_type == TokenType::equal || token_type == TokenType::not_equal || token_type == TokenType::greater || token_type == TokenType::greater_equal ||
|
||||||
|
token_type == TokenType::lesser || token_type == TokenType::lesser_equal);
|
||||||
|
}
|
||||||
|
|
||||||
|
TokenType Lexer::type(const std::string &token) {
|
||||||
|
// TODO move it to class level not to reinit it again and again
|
||||||
|
std::regex int_regex("[0-9]+");
|
||||||
|
std::regex int_underscored_regex("[0-9][0-9_]+[0-9]");
|
||||||
|
std::regex double_regex("[0-9]+\\.[0-9]+");
|
||||||
|
std::regex identifier_regex("[A-Za-z]+[A-Za-z0-9_#]*");
|
||||||
|
|
||||||
|
if (token == ";")
|
||||||
|
return TokenType::semicolon;
|
||||||
|
|
||||||
|
if (token == "+")
|
||||||
|
return TokenType::plus;
|
||||||
|
|
||||||
|
if (token == "-")
|
||||||
|
return TokenType::minus;
|
||||||
|
|
||||||
|
if (token == "*")
|
||||||
|
return TokenType::multiply;
|
||||||
|
|
||||||
|
if (token == "/")
|
||||||
|
return TokenType::divide;
|
||||||
|
|
||||||
|
if (token == "(")
|
||||||
|
return TokenType::open_paren;
|
||||||
|
|
||||||
|
if (token == ")")
|
||||||
|
return TokenType::close_paren;
|
||||||
|
|
||||||
|
if (token == "=")
|
||||||
|
return TokenType::equal;
|
||||||
|
|
||||||
|
if (token == "!=")
|
||||||
|
return TokenType::not_equal;
|
||||||
|
|
||||||
|
if (token == ">")
|
||||||
|
return TokenType::greater;
|
||||||
|
|
||||||
|
if (token == ">=")
|
||||||
|
return TokenType::greater_equal;
|
||||||
|
|
||||||
|
if (token == "<")
|
||||||
|
return TokenType::lesser;
|
||||||
|
|
||||||
|
if (token == "<=")
|
||||||
|
return TokenType::lesser_equal;
|
||||||
|
|
||||||
|
if (token == "create")
|
||||||
|
return TokenType::keyword_create;
|
||||||
|
|
||||||
|
if (token == "where")
|
||||||
|
return TokenType::keyword_where;
|
||||||
|
|
||||||
|
if (token == "from")
|
||||||
|
return TokenType::keyword_from;
|
||||||
|
|
||||||
|
if (token == "table")
|
||||||
|
return TokenType::keyword_table;
|
||||||
|
|
||||||
|
if (token == "insert")
|
||||||
|
return TokenType::keyword_insert;
|
||||||
|
|
||||||
|
if (token == "into")
|
||||||
|
return TokenType::keyword_into;
|
||||||
|
|
||||||
|
if (token == "values")
|
||||||
|
return TokenType::keyword_values;
|
||||||
|
|
||||||
|
if (token == "select")
|
||||||
|
return TokenType::keyword_select;
|
||||||
|
|
||||||
|
if (token == "set")
|
||||||
|
return TokenType::keyword_set;
|
||||||
|
|
||||||
|
if (token == "copy")
|
||||||
|
return TokenType::keyword_copy;
|
||||||
|
|
||||||
|
if (token == "not")
|
||||||
|
return TokenType::keyword_not;
|
||||||
|
|
||||||
|
if (token == "null")
|
||||||
|
return TokenType::keyword_null;
|
||||||
|
|
||||||
|
if (token == "integer")
|
||||||
|
return TokenType::keyword_int;
|
||||||
|
|
||||||
|
if (token == "float")
|
||||||
|
return TokenType::keyword_float;
|
||||||
|
|
||||||
|
if (token == "varchar")
|
||||||
|
return TokenType::keyword_varchar;
|
||||||
|
|
||||||
|
if (token == "||")
|
||||||
|
return TokenType::logical_or;
|
||||||
|
|
||||||
|
if (token == "&&")
|
||||||
|
return TokenType::logical_and;
|
||||||
|
|
||||||
|
if (token == ",")
|
||||||
|
return TokenType::comma;
|
||||||
|
|
||||||
|
if (token == "\n" || token == "\r\n" || token == "\r")
|
||||||
|
return TokenType::newline;
|
||||||
|
|
||||||
|
if (token.length() > 1 && token.at(0) == '%' && (token.at(token.length() - 1) == '\n' || token.at(token.length() - 1) == '\r'))
|
||||||
|
return TokenType::comment;
|
||||||
|
|
||||||
|
// if (token.length() >= 2 && token.at(0) == '"' && token.at(token.length() - 1) == '"')
|
||||||
|
// return TokenType::string_literal;
|
||||||
|
|
||||||
|
if (token.length() >= 2 && token.at(0) == '\'' && token.at(token.length() - 1) == '\'')
|
||||||
|
return TokenType::string_literal;
|
||||||
|
|
||||||
|
if (std::regex_match(token, int_regex))
|
||||||
|
return TokenType::int_number;
|
||||||
|
|
||||||
|
if (std::regex_match(token, int_underscored_regex))
|
||||||
|
return TokenType::int_number;
|
||||||
|
|
||||||
|
if (std::regex_match(token, double_regex))
|
||||||
|
return TokenType::double_number;
|
||||||
|
|
||||||
|
if (std::regex_match(token, identifier_regex))
|
||||||
|
return TokenType::identifier;
|
||||||
|
|
||||||
|
if (index + 1 >= tokens.size())
|
||||||
|
return TokenType::eof;
|
||||||
|
|
||||||
|
return TokenType::undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Lexer::stringLiteral(std::string token) {
|
||||||
|
// remove ' or " from the literal ends
|
||||||
|
bool replace = token[0]=='\'' && token[token.size()-1]=='\'';
|
||||||
|
|
||||||
|
std::string str = token.substr(1, token.size() - 2);
|
||||||
|
if (!replace) {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
std::string out = "";
|
||||||
|
out.reserve(str.size());
|
||||||
|
|
||||||
|
|
||||||
|
for(std::string::size_type i = 0; i < str.size(); ++i) {
|
||||||
|
if (str[i] == '\'' && i < str.size() - 1) {
|
||||||
|
if (str[i+1] == '\'') {
|
||||||
|
out.append(1, '\'');
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
out.append(1, str[i]);
|
||||||
|
}
|
||||||
|
} else if (str[i] == '\\' && i < str.size() - 1) {
|
||||||
|
if (str[i+1] == 'n') {
|
||||||
|
out.append(1, '\n');
|
||||||
|
i++;
|
||||||
|
} else if (str[i+1] == 't') {
|
||||||
|
out.append(1, '\t');
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
out.append(1, str[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.append(1, str[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Lexer::typeToString(TokenType token_type) {
|
||||||
|
std::string txt;
|
||||||
|
switch (token_type) {
|
||||||
|
case TokenType::undef:
|
||||||
|
txt = "undef";
|
||||||
|
break;
|
||||||
|
case TokenType::identifier:
|
||||||
|
txt = "identifier";
|
||||||
|
break;
|
||||||
|
case TokenType::plus:
|
||||||
|
txt = "+";
|
||||||
|
break;
|
||||||
|
case TokenType::minus:
|
||||||
|
txt = "-";
|
||||||
|
break;
|
||||||
|
case TokenType::multiply:
|
||||||
|
txt = "*";
|
||||||
|
break;
|
||||||
|
case TokenType::divide:
|
||||||
|
txt = "/";
|
||||||
|
break;
|
||||||
|
case TokenType::equal:
|
||||||
|
txt = "==";
|
||||||
|
break;
|
||||||
|
case TokenType::not_equal:
|
||||||
|
txt = "!=";
|
||||||
|
break;
|
||||||
|
case TokenType::greater:
|
||||||
|
txt = ">";
|
||||||
|
break;
|
||||||
|
case TokenType::greater_equal:
|
||||||
|
txt = ">=";
|
||||||
|
break;
|
||||||
|
case TokenType::lesser:
|
||||||
|
txt = "<";
|
||||||
|
break;
|
||||||
|
case TokenType::lesser_equal:
|
||||||
|
txt = "<=";
|
||||||
|
break;
|
||||||
|
case TokenType::keyword_create:
|
||||||
|
txt = "create";
|
||||||
|
break;
|
||||||
|
case TokenType::keyword_where:
|
||||||
|
txt = "where";
|
||||||
|
break;
|
||||||
|
case TokenType::keyword_table:
|
||||||
|
txt = "table";
|
||||||
|
break;
|
||||||
|
case TokenType::keyword_into:
|
||||||
|
txt = "into";
|
||||||
|
break;
|
||||||
|
case TokenType::keyword_values:
|
||||||
|
txt = "values";
|
||||||
|
break;
|
||||||
|
case TokenType::keyword_select:
|
||||||
|
txt = "select";
|
||||||
|
break;
|
||||||
|
case TokenType::keyword_set:
|
||||||
|
txt = "set";
|
||||||
|
break;
|
||||||
|
case TokenType::keyword_copy:
|
||||||
|
txt = "copy";
|
||||||
|
break;
|
||||||
|
case TokenType::keyword_not:
|
||||||
|
txt = "not";
|
||||||
|
break;
|
||||||
|
case TokenType::keyword_null:
|
||||||
|
txt = "null";
|
||||||
|
break;
|
||||||
|
case TokenType::keyword_int:
|
||||||
|
txt = "integer";
|
||||||
|
break;
|
||||||
|
case TokenType::keyword_float:
|
||||||
|
txt = "float";
|
||||||
|
break;
|
||||||
|
case TokenType::keyword_varchar:
|
||||||
|
txt = "varchar";
|
||||||
|
break;
|
||||||
|
case TokenType::int_number:
|
||||||
|
txt = "int number";
|
||||||
|
break;
|
||||||
|
case TokenType::double_number:
|
||||||
|
txt = "double number";
|
||||||
|
break;
|
||||||
|
case TokenType::string_literal:
|
||||||
|
txt = "string literal";
|
||||||
|
break;
|
||||||
|
case TokenType::open_paren:
|
||||||
|
txt = "(";
|
||||||
|
break;
|
||||||
|
case TokenType::close_paren:
|
||||||
|
txt = ")";
|
||||||
|
break;
|
||||||
|
case TokenType::logical_and:
|
||||||
|
txt = "and";
|
||||||
|
break;
|
||||||
|
case TokenType::logical_or:
|
||||||
|
txt = "or";
|
||||||
|
break;
|
||||||
|
case TokenType::semicolon:
|
||||||
|
txt = ";";
|
||||||
|
break;
|
||||||
|
case TokenType::comma:
|
||||||
|
txt = ",";
|
||||||
|
break;
|
||||||
|
case TokenType::newline:
|
||||||
|
txt = "newline";
|
||||||
|
break;
|
||||||
|
case TokenType::comment:
|
||||||
|
txt = "comment";
|
||||||
|
break;
|
||||||
|
case TokenType::eof:
|
||||||
|
txt = "eof";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
txt = "FIXME, unknown token type";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return txt;
|
||||||
|
}
|
||||||
87
lexer.h
Normal file
87
lexer.h
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <regex>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
enum class TokenType {
|
||||||
|
undef,
|
||||||
|
identifier,
|
||||||
|
plus,
|
||||||
|
minus,
|
||||||
|
multiply,
|
||||||
|
divide,
|
||||||
|
equal,
|
||||||
|
not_equal,
|
||||||
|
greater,
|
||||||
|
greater_equal,
|
||||||
|
lesser,
|
||||||
|
lesser_equal,
|
||||||
|
keyword_create,
|
||||||
|
keyword_table,
|
||||||
|
keyword_where,
|
||||||
|
keyword_from,
|
||||||
|
keyword_insert,
|
||||||
|
keyword_into,
|
||||||
|
keyword_values,
|
||||||
|
keyword_select,
|
||||||
|
keyword_set,
|
||||||
|
keyword_copy,
|
||||||
|
keyword_not,
|
||||||
|
keyword_null,
|
||||||
|
keyword_int,
|
||||||
|
keyword_float,
|
||||||
|
keyword_varchar,
|
||||||
|
int_number,
|
||||||
|
double_number,
|
||||||
|
string_literal,
|
||||||
|
open_paren,
|
||||||
|
close_paren,
|
||||||
|
logical_and,
|
||||||
|
logical_or,
|
||||||
|
semicolon,
|
||||||
|
comma,
|
||||||
|
newline,
|
||||||
|
comment,
|
||||||
|
eof
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Token {
|
||||||
|
std::string token_string;
|
||||||
|
TokenType type;
|
||||||
|
Token(const std::string &token_str, TokenType typ);
|
||||||
|
};
|
||||||
|
|
||||||
|
class Lexer {
|
||||||
|
private:
|
||||||
|
std::string code_str;
|
||||||
|
std::vector<Token> tokens;
|
||||||
|
int index = 0;
|
||||||
|
bool eof = false;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Lexer() {};
|
||||||
|
|
||||||
|
void parse(const std::string &code);
|
||||||
|
|
||||||
|
void debugTokens();
|
||||||
|
|
||||||
|
Token currentToken();
|
||||||
|
|
||||||
|
void nextToken();
|
||||||
|
|
||||||
|
void skipToken(TokenType type);
|
||||||
|
void skipTokenOptional(TokenType type);
|
||||||
|
|
||||||
|
TokenType tokenType();
|
||||||
|
TokenType nextTokenType();
|
||||||
|
TokenType prevTokenType();
|
||||||
|
|
||||||
|
static bool isRelationalOperator(TokenType token_type);
|
||||||
|
|
||||||
|
private:
|
||||||
|
TokenType type(const std::string &token);
|
||||||
|
std::string stringLiteral(std::string token);
|
||||||
|
static std::string typeToString(TokenType token_type);
|
||||||
|
};
|
||||||
26
main.cpp
Normal file
26
main.cpp
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#include "parser.h"
|
||||||
|
#include "executor.h"
|
||||||
|
|
||||||
|
// https://dev.to/joaoh82/what-would-sqlite-look-like-if-written-in-rust-part-1-2np4
|
||||||
|
|
||||||
|
// parser should get lexer as param and table executor to be able translate * or get types or so
|
||||||
|
// podporovat create as select
|
||||||
|
// drop table
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
Parser parser{};
|
||||||
|
Executor executor{};
|
||||||
|
|
||||||
|
std::string sql_create = "create table a (i integer not null, s varchar(64), f float)";
|
||||||
|
// std::string sql_insert = "insert into a (i, s) values(1, 'one')";
|
||||||
|
// std::string sql_inser2 = "insert into a (i, s) values(2, 'two')";
|
||||||
|
// std::string sql_inser3 = "insert into a (i, s) values(3, 'two')";
|
||||||
|
// std::string sql_update = "update a set s = 'three' where i = 3";
|
||||||
|
// std::string sql_select = "select i, s from a where i > 0";
|
||||||
|
// std::string sql_delete = "delete from a where i = 3";
|
||||||
|
|
||||||
|
auto node = parser.parse(sql_create);
|
||||||
|
|
||||||
|
executor.execute(*node.get());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
87
parser.cpp
Normal file
87
parser.cpp
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
#include "parser.h"
|
||||||
|
#include "exception.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Parser::Parser() {
|
||||||
|
lexer = Lexer{};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Node> Parser::parse(const std::string &code) {
|
||||||
|
lexer.parse(code);
|
||||||
|
lexer.debugTokens();
|
||||||
|
|
||||||
|
if (lexer.tokenType() == TokenType::keyword_create && lexer.nextTokenType() == TokenType::keyword_table) {
|
||||||
|
return parse_create_table();
|
||||||
|
} if (lexer.tokenType() == TokenType::keyword_select) {
|
||||||
|
return parse_select();
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_unique<Node>(NodeType::error);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Node> Parser::parse_create_table() {
|
||||||
|
std::vector<ColDefNode> cols_def {};
|
||||||
|
|
||||||
|
lexer.skipToken(TokenType::keyword_create);
|
||||||
|
lexer.skipToken(TokenType::keyword_table);
|
||||||
|
|
||||||
|
if (lexer.tokenType() != TokenType::identifier) { /* TODO handle error */ }
|
||||||
|
std::string table_name = lexer.currentToken().token_string;
|
||||||
|
lexer.nextToken();
|
||||||
|
|
||||||
|
lexer.skipToken(TokenType::open_paren);
|
||||||
|
do {
|
||||||
|
std::string column_name;
|
||||||
|
ColumnType column_type;
|
||||||
|
int column_len {1};
|
||||||
|
bool column_nullable {true};
|
||||||
|
|
||||||
|
// column name
|
||||||
|
if (lexer.tokenType() != TokenType::identifier) { /* TODO handle error */ }
|
||||||
|
column_name = lexer.currentToken().token_string;
|
||||||
|
lexer.nextToken();
|
||||||
|
|
||||||
|
// column type and optionaly len
|
||||||
|
if (lexer.tokenType() == TokenType::keyword_int) {
|
||||||
|
column_type = ColumnType::integer_type;
|
||||||
|
lexer.nextToken();
|
||||||
|
} else if (lexer.tokenType() == TokenType::keyword_float) {
|
||||||
|
column_type = ColumnType::float_type;
|
||||||
|
lexer.nextToken();
|
||||||
|
} else if (lexer.tokenType() == TokenType::keyword_varchar) {
|
||||||
|
column_type = ColumnType::varchar_type;
|
||||||
|
lexer.nextToken();
|
||||||
|
lexer.skipToken(TokenType::open_paren);
|
||||||
|
if (lexer.tokenType() == TokenType::int_number) {
|
||||||
|
column_len = std::stoi(lexer.currentToken().token_string);
|
||||||
|
lexer.nextToken();
|
||||||
|
} else { /* TODO handle error */ }
|
||||||
|
lexer.skipToken(TokenType::close_paren);
|
||||||
|
} else { /* TODO handle error */ }
|
||||||
|
|
||||||
|
if (lexer.tokenType() == TokenType::keyword_not) {
|
||||||
|
lexer.nextToken();
|
||||||
|
lexer.skipToken(TokenType::keyword_null);
|
||||||
|
column_nullable = false;
|
||||||
|
} else if (lexer.tokenType() == TokenType::keyword_null) {
|
||||||
|
lexer.nextToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
cols_def.push_back(ColDefNode(column_name, column_type, column_len, column_nullable));
|
||||||
|
|
||||||
|
if (lexer.tokenType() == TokenType::comma) lexer.nextToken();
|
||||||
|
|
||||||
|
// TODO in future constraints
|
||||||
|
|
||||||
|
} while (lexer.tokenType() != TokenType::close_paren);
|
||||||
|
|
||||||
|
|
||||||
|
return std::make_unique<CreateTableNode>(table_name, cols_def);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Node> Parser::parse_select() {
|
||||||
|
std::vector<Node> exec_code {};
|
||||||
|
|
||||||
|
return std::make_unique<Node>(NodeType::not_implemented_yet);
|
||||||
|
}
|
||||||
63
parser.h
Normal file
63
parser.h
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "lexer.h"
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
|
enum class ColumnType {
|
||||||
|
integer_type,
|
||||||
|
float_type,
|
||||||
|
varchar_type
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class NodeType {
|
||||||
|
create_table,
|
||||||
|
select_from,
|
||||||
|
column_def,
|
||||||
|
not_implemented_yet,
|
||||||
|
error
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Node {
|
||||||
|
NodeType node_type;
|
||||||
|
|
||||||
|
Node(const NodeType type) : node_type(type) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ColDefNode : Node {
|
||||||
|
std::string name;
|
||||||
|
ColumnType type;
|
||||||
|
int length;
|
||||||
|
bool null;
|
||||||
|
|
||||||
|
ColDefNode(const std::string col_name, const ColumnType col_type, int col_len, bool nullable) :
|
||||||
|
Node(NodeType::column_def), name(col_name), type(col_type), length(col_len), null(nullable) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CreateTableNode : Node {
|
||||||
|
std::string table_name;
|
||||||
|
std::vector<ColDefNode> cols_defs;
|
||||||
|
|
||||||
|
CreateTableNode(const std::string name, std::vector<ColDefNode> defs) :
|
||||||
|
Node(NodeType::create_table), table_name(name), cols_defs(defs) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Parser {
|
||||||
|
private:
|
||||||
|
|
||||||
|
public:
|
||||||
|
Parser();
|
||||||
|
|
||||||
|
std::unique_ptr<Node> parse(const std::string &code);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<Node> parse_create_table();
|
||||||
|
std::unique_ptr<Node> parse_select();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Lexer lexer;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user