Cleanup, restructuring
This commit is contained in:
parent
fc035bd7a7
commit
eddfeb7bfc
|
@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
project(biscuit_interpreter)
|
project(biscuit_interpreter)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
|
|
||||||
add_executable(biscuit_interpreter src/common.hpp)
|
add_executable(biscuit_interpreter src/common.hpp)
|
||||||
|
|
|
@ -12,7 +12,7 @@ enum TokenType
|
||||||
enum ValueType
|
enum ValueType
|
||||||
{
|
{
|
||||||
STRING,
|
STRING,
|
||||||
DECIMAL,
|
NUMBER,
|
||||||
ANY
|
ANY
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
45
src/exceptions.hpp
Normal file
45
src/exceptions.hpp
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#ifndef BISCUIT_INTERPRETER_EXCEPTIONS_HPP
|
||||||
|
#define BISCUIT_INTERPRETER_EXCEPTIONS_HPP
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
#include "common.hpp"
|
||||||
|
|
||||||
|
struct MalformedTokenExcept : public std::exception
|
||||||
|
{
|
||||||
|
std::string malformed_str;
|
||||||
|
inline MalformedTokenExcept(const std::string& arg_str)
|
||||||
|
: malformed_str(arg_str) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UnknownKeywordExcept : public std::exception
|
||||||
|
{
|
||||||
|
std::string unknown_keyword;
|
||||||
|
inline UnknownKeywordExcept(const std::string& arg_str)
|
||||||
|
: unknown_keyword(arg_str) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WrongArgumentCountExcept : public std::exception
|
||||||
|
{
|
||||||
|
int expected, got;
|
||||||
|
std::string keyword_name;
|
||||||
|
inline WrongArgumentCountExcept(const std::string& _name, int _expected, int _got)
|
||||||
|
: expected(_expected), got(_got), keyword_name(_name) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WrongTokenExcept : public std::exception
|
||||||
|
{
|
||||||
|
enum TokenType expected, got;
|
||||||
|
std::string keyword_name, token_str;
|
||||||
|
inline WrongTokenExcept(const std::string& _keyword_name, const std::string& _token_str, const enum TokenType& _expected, const enum TokenType& _got)
|
||||||
|
: expected(_expected), got(_got), keyword_name(_keyword_name), token_str(_token_str) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TypeErrorExcept : public std::exception
|
||||||
|
{
|
||||||
|
enum ValueType expected, got;
|
||||||
|
std::string keyword_name, token_str;
|
||||||
|
inline TypeErrorExcept(const std::string& _keyword_name, const std::string& _token_str, const enum ValueType& _expected, const enum ValueType& _got)
|
||||||
|
: expected(_expected), got(_got), keyword_name(_keyword_name), token_str(_token_str) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //BISCUIT_INTERPRETER_EXCEPTIONS_HPP
|
|
@ -12,8 +12,8 @@ struct Keyword
|
||||||
const std::string name;
|
const std::string name;
|
||||||
const int expected_num_args; // -1 means: 1 to infinity, in which case all args are of same type
|
const int expected_num_args; // -1 means: 1 to infinity, in which case all args are of same type
|
||||||
|
|
||||||
const std::vector<TokenType> expected_token_types;
|
const std::vector<enum TokenType> expected_token_types;
|
||||||
const std::vector<ValueType> expected_value_types;
|
const std::vector<enum ValueType> expected_value_types;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const std::vector<Keyword> keywords;
|
extern const std::vector<Keyword> keywords;
|
||||||
|
|
74
src/main.cpp
74
src/main.cpp
|
@ -1,10 +1,32 @@
|
||||||
|
#if defined(WIN32) || defined(WIN32) || defined(__WIN32)
|
||||||
|
#include <Windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "common.hpp"
|
||||||
|
#include "exceptions.hpp"
|
||||||
#include "parse.hpp"
|
#include "parse.hpp"
|
||||||
|
|
||||||
|
bool request_console();
|
||||||
|
|
||||||
|
// Must request console on Windows
|
||||||
|
#if defined(WIN32) || defined(WIN32) || defined(__WIN32)
|
||||||
|
bool request_console()
|
||||||
|
{
|
||||||
|
return AllocConsole();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
bool request_console()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
std::ifstream get_infile(int argc, char ** argv)
|
std::ifstream get_infile(int argc, char ** argv)
|
||||||
{
|
{
|
||||||
if(argc != 2)
|
if(argc != 2)
|
||||||
|
@ -24,40 +46,34 @@ std::ifstream get_infile(int argc, char ** argv)
|
||||||
return infile;
|
return infile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string code = \
|
||||||
|
R"del(
|
||||||
|
PRINT 10.0 |hello_world
|
||||||
|
)del";
|
||||||
|
|
||||||
int main(int argc, char * argv[])
|
int main(int argc, char * argv[])
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
// Get the entire source code from the file
|
||||||
std::ifstream infile = get_infile(argc, argv);
|
std::ifstream infile = get_infile(argc, argv);
|
||||||
std::string word;
|
std::stringstream buffer;
|
||||||
std::vector<Token> tokens;
|
buffer << infile.rdbuf();
|
||||||
|
*/
|
||||||
|
|
||||||
while(infile >> word)
|
// On Windows, we have to explicitly request a console
|
||||||
{
|
/*if(!request_console())
|
||||||
try
|
{
|
||||||
{
|
std::cerr << "Failed to get console!" << std::endl;
|
||||||
Token token(word);
|
exit(EXIT_FAILURE);
|
||||||
tokens.push_back(token);
|
}*/
|
||||||
}
|
|
||||||
catch(MalformedIdentifierExcept& exc)
|
|
||||||
{
|
|
||||||
std::cout << "Malformed identifier: '" << exc.malformed_str << "'"
|
|
||||||
<< "\nAborting..." << std::endl;
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
catch(UnknownKeywordExcept& exc)
|
|
||||||
{
|
|
||||||
std::cout << "Unknown Keyword: '" << exc.unknown_keyword << "'"
|
|
||||||
<< "\nAborting..." << std::endl;
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
catch(WrongTokenExcept& exc)
|
|
||||||
{
|
|
||||||
std::cout << "Wrong symbol type\n Aborting..." << std::endl;
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Instruction instr(tokens);
|
std::cerr << "POOP" << std::endl;
|
||||||
instr.print();
|
|
||||||
|
std::vector<Instruction> instructions = parse_instructions(code);
|
||||||
|
|
||||||
|
std::cerr << "Number of instructions parsed: " << instructions.size() << std::endl;
|
||||||
|
for(auto& instr : instructions)
|
||||||
|
instr.print();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,72 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "exceptions.hpp"
|
||||||
#include "keywords.hpp"
|
#include "keywords.hpp"
|
||||||
#include "parse.hpp"
|
#include "parse.hpp"
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
|
|
||||||
|
static const std::string blank_space = "\t ";
|
||||||
|
static const std::string line_end = "\n";
|
||||||
|
|
||||||
|
// turn a line (one instruction) into tokens
|
||||||
|
std::vector<Token> tokenize_line(const std::string& line)
|
||||||
|
{
|
||||||
|
std::vector<Token> tokens;
|
||||||
|
|
||||||
|
// find all individual tokens
|
||||||
|
std::size_t end, begin = line.find_first_not_of(blank_space, 0);
|
||||||
|
while(begin != std::string::npos)
|
||||||
|
{
|
||||||
|
end = line.find_first_of(blank_space, begin);
|
||||||
|
std::string word = line.substr(begin, end - begin);
|
||||||
|
tokens.emplace_back(word);
|
||||||
|
|
||||||
|
begin = line.find_first_not_of(blank_space, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::move(tokens);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Instruction> parse_instructions(const std::string& code_arg)
|
||||||
|
{
|
||||||
|
// Make a copy of the code and append a line_end symbol to make sure the
|
||||||
|
// parser doesn't break on EOF
|
||||||
|
std::string code = code_arg;
|
||||||
|
code.append(line_end);
|
||||||
|
|
||||||
|
std::vector<Instruction> instructions;
|
||||||
|
|
||||||
|
std::size_t end, begin = code.find_first_not_of(line_end, 0);
|
||||||
|
while(begin != std::string::npos)
|
||||||
|
{
|
||||||
|
end = code.find_first_of(line_end, begin);
|
||||||
|
std::string line = code.substr(begin, end - begin);
|
||||||
|
std::vector<Token> tokens = tokenize_line(line);
|
||||||
|
instructions.emplace_back(tokens);
|
||||||
|
|
||||||
|
begin = code.find_first_not_of(line_end, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::move(instructions);
|
||||||
|
}
|
||||||
|
|
||||||
bool is_keyword(std::string str)
|
bool is_keyword(std::string str)
|
||||||
{
|
{
|
||||||
for(char &c : str)
|
for(char &c : str)
|
||||||
c = std::tolower(c);
|
c = (char) std::tolower(c);
|
||||||
|
|
||||||
for(auto &keyword : keywords)
|
return std::any_of(keywords.begin(), keywords.end(),[&str](auto& keyword){
|
||||||
|
return keyword.name == str;
|
||||||
|
});
|
||||||
|
|
||||||
|
/* for(auto &keyword : keywords)
|
||||||
if(str == keyword.name)
|
if(str == keyword.name)
|
||||||
return true;
|
return true;
|
||||||
return 0;
|
return 0;
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_string_literal(const std::string& str)
|
bool is_string_literal(const std::string& str)
|
||||||
|
@ -70,7 +121,7 @@ bool Token::parse_as_literal(const std::string &str)
|
||||||
else if(is_decimal_literal(str))
|
else if(is_decimal_literal(str))
|
||||||
{
|
{
|
||||||
type = TokenType::LITERAL;
|
type = TokenType::LITERAL;
|
||||||
literal_type = ValueType::DECIMAL;
|
literal_type = ValueType::NUMBER;
|
||||||
val_float = std::stof(str);
|
val_float = std::stof(str);
|
||||||
val_string = str;
|
val_string = str;
|
||||||
return true;
|
return true;
|
||||||
|
@ -86,7 +137,9 @@ bool Token::parse_as_identifier(const std::string &str)
|
||||||
if(is_identifier(str))
|
if(is_identifier(str))
|
||||||
{
|
{
|
||||||
type = TokenType::IDENTIFIER;
|
type = TokenType::IDENTIFIER;
|
||||||
|
literal_type = ValueType::ANY;
|
||||||
val_string = str;
|
val_string = str;
|
||||||
|
val_float = 0.0f;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -94,13 +147,9 @@ bool Token::parse_as_identifier(const std::string &str)
|
||||||
|
|
||||||
Token::Token(const std::string &str)
|
Token::Token(const std::string &str)
|
||||||
{
|
{
|
||||||
if (parse_as_keyword(str));
|
// First try to parse as str, then as literal, then as identifier
|
||||||
else if(parse_as_literal(str));
|
if(!(parse_as_keyword(str) && parse_as_literal(str) && parse_as_identifier(str)))
|
||||||
else if(parse_as_identifier(str));
|
throw MalformedTokenExcept(str); // if all fails -> malformed token
|
||||||
else
|
|
||||||
{
|
|
||||||
throw MalformedIdentifierExcept(str);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Token::print() const
|
void Token::print() const
|
||||||
|
@ -116,7 +165,7 @@ void Token::print() const
|
||||||
|
|
||||||
case TokenType::LITERAL:
|
case TokenType::LITERAL:
|
||||||
std::cerr << "Literal of type ";
|
std::cerr << "Literal of type ";
|
||||||
if(literal_type == ValueType::DECIMAL)
|
if(literal_type == ValueType::NUMBER)
|
||||||
std::cerr << "decimal: " << val_float;
|
std::cerr << "decimal: " << val_float;
|
||||||
else if(literal_type == ValueType::STRING)
|
else if(literal_type == ValueType::STRING)
|
||||||
std::cerr << "string: \"" << val_string << "\"";
|
std::cerr << "string: \"" << val_string << "\"";
|
||||||
|
@ -128,8 +177,6 @@ void Token::print() const
|
||||||
std::cerr << std::endl;
|
std::cerr << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Instruction::Instruction(std::vector<Token>& _token_list)
|
Instruction::Instruction(std::vector<Token>& _token_list)
|
||||||
{
|
{
|
||||||
// move over the tokens
|
// move over the tokens
|
||||||
|
|
|
@ -1,61 +1,21 @@
|
||||||
#ifndef BISCUIT_PARSE_HPP_INCLUDED
|
#ifndef BISCUIT_PARSE_HPP_INCLUDED
|
||||||
#define BISCUIT_PARSE_HPP_INCLUDED
|
#define BISCUIT_PARSE_HPP_INCLUDED
|
||||||
|
|
||||||
#include <exception>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "keywords.hpp"
|
#include "keywords.hpp"
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
|
|
||||||
struct MalformedIdentifierExcept : public std::exception
|
|
||||||
{
|
|
||||||
std::string malformed_str;
|
|
||||||
MalformedIdentifierExcept(const std::string& arg_str)
|
|
||||||
: malformed_str(arg_str) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct UnknownKeywordExcept : public std::exception
|
|
||||||
{
|
|
||||||
std::string unknown_keyword;
|
|
||||||
UnknownKeywordExcept(const std::string& arg_str)
|
|
||||||
: unknown_keyword(arg_str) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct WrongArgumentCountExcept : public std::exception
|
|
||||||
{
|
|
||||||
int expected, got;
|
|
||||||
std::string keyword_name;
|
|
||||||
WrongArgumentCountExcept(std::string _name, int _expected, int _got)
|
|
||||||
: expected(_expected), got(_got), keyword_name(_name) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct WrongTokenExcept : public std::exception
|
|
||||||
{
|
|
||||||
TokenType expected, got;
|
|
||||||
std::string keyword_name, token_str;
|
|
||||||
WrongTokenExcept(std::string _keyword_name, std::string _token_str, const TokenType& _expected, const TokenType& _got)
|
|
||||||
: expected(_expected), got(_got), keyword_name(_keyword_name), token_str(_token_str) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TypeErrorExcept : public std::exception
|
|
||||||
{
|
|
||||||
ValueType expected, got;
|
|
||||||
std::string keyword_name, token_str;
|
|
||||||
TypeErrorExcept(std::string _keyword_name, std::string _token_str, const ValueType& _expected, const ValueType& _got)
|
|
||||||
: expected(_expected), got(_got), keyword_name(_keyword_name), token_str(_token_str) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct Token
|
struct Token
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
bool parse_as_keyword(const std::string &str);
|
bool parse_as_keyword(const std::string& str);
|
||||||
|
|
||||||
bool parse_as_literal(const std::string &str);
|
bool parse_as_literal(const std::string& str);
|
||||||
|
|
||||||
// if a word is not a keyword or literal, it must be identifier
|
// if a word is not a keyword or literal, it must be identifier
|
||||||
bool parse_as_identifier(const std::string &str);
|
bool parse_as_identifier(const std::string& str);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum TokenType type;
|
enum TokenType type;
|
||||||
|
@ -63,7 +23,7 @@ public:
|
||||||
float val_float;
|
float val_float;
|
||||||
std::string val_string;
|
std::string val_string;
|
||||||
|
|
||||||
Token(const std::string &str);
|
Token(const std::string& str);
|
||||||
|
|
||||||
void print() const;
|
void print() const;
|
||||||
};
|
};
|
||||||
|
@ -79,4 +39,6 @@ public:
|
||||||
void print();
|
void print();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::vector<Instruction> parse_instructions(const std::string& code_arg);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue