Initial commit
This commit is contained in:
commit
02afb71c84
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
build
|
14
CMakeLists.txt
Normal file
14
CMakeLists.txt
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
|
project(biscuit_interpreter)
|
||||||
|
|
||||||
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
|
|
||||||
|
add_executable(biscuit_interpreter)
|
||||||
|
|
||||||
|
target_sources( biscuit_interpreter PRIVATE
|
||||||
|
src/main.cpp
|
||||||
|
src/parse.cpp
|
||||||
|
src/keywords.cpp )
|
||||||
|
|
||||||
|
include_directories(${CMAKE_SOURCE_DIR})
|
BIN
biscuit_doc.odt
Normal file
BIN
biscuit_doc.odt
Normal file
Binary file not shown.
2
examples/helloworld.bisc
Normal file
2
examples/helloworld.bisc
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
print #hello_world
|
||||||
|
print 1.01234
|
18
src/.ycm_extra_conf.py
Normal file
18
src/.ycm_extra_conf.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import os
|
||||||
|
import ycm_core
|
||||||
|
|
||||||
|
flags = [
|
||||||
|
'-Wall',
|
||||||
|
'-Wextra',
|
||||||
|
'-Wno-long-long',
|
||||||
|
'-Wno-variadic-macros',
|
||||||
|
'-std=c++20',
|
||||||
|
]
|
||||||
|
|
||||||
|
SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '.cc', '.c', ]
|
||||||
|
|
||||||
|
def FlagsForFile( filename, **kwargs ):
|
||||||
|
return {
|
||||||
|
'flags': flags,
|
||||||
|
'do_cache': True
|
||||||
|
}
|
18
src/keywords.cpp
Normal file
18
src/keywords.cpp
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#include <string>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include "keywords.hpp"
|
||||||
|
|
||||||
|
const std::vector<Keyword> keywords =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.name = "print",
|
||||||
|
.expected_num_args = -1,
|
||||||
|
.expected_token_types = {TokenType::ID_OR_LIT},
|
||||||
|
.expected_value_types = {ValueType::ANY}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "exit",
|
||||||
|
.expected_num_args = 0
|
||||||
|
}
|
||||||
|
};
|
20
src/keywords.hpp
Normal file
20
src/keywords.hpp
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#ifndef BISCUIT_KEYWORDS_HPP_INCLUDED
|
||||||
|
#define BISCUIT_KEYWORDS_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <array>
|
||||||
|
#include "parse.hpp"
|
||||||
|
|
||||||
|
struct Keyword
|
||||||
|
{
|
||||||
|
const std::string name;
|
||||||
|
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<ValueType> expected_value_types;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const std::vector<Keyword> keywords;
|
||||||
|
|
||||||
|
#endif
|
61
src/main.cpp
Normal file
61
src/main.cpp
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <array>
|
||||||
|
#include <fstream>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
|
#include "parse.hpp"
|
||||||
|
|
||||||
|
std::ifstream get_infile(int argc, char ** argv)
|
||||||
|
{
|
||||||
|
if(argc != 2)
|
||||||
|
{
|
||||||
|
std::cerr << "Usage: " << argv[0] << " <infile>" << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ifstream infile(argv[1]);
|
||||||
|
|
||||||
|
if(!infile)
|
||||||
|
{
|
||||||
|
std::cerr << "Could not open '" << argv[1] << "'" << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return infile;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char * argv[])
|
||||||
|
{
|
||||||
|
std::ifstream infile = get_infile(argc, argv);
|
||||||
|
std::string word;
|
||||||
|
while(infile >> word)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Symbol sym(word);
|
||||||
|
sym.print();
|
||||||
|
}
|
||||||
|
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(WrongSymbolExcept& exc)
|
||||||
|
{
|
||||||
|
std::cout << "Wrong symbol type\n Aborting..." << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
148
src/parse.cpp
Normal file
148
src/parse.cpp
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <exception>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include "keywords.hpp"
|
||||||
|
#include "parse.hpp"
|
||||||
|
|
||||||
|
bool is_keyword(std::string str)
|
||||||
|
{
|
||||||
|
for(char &c : str)
|
||||||
|
c = std::tolower(c);
|
||||||
|
|
||||||
|
for(auto &keyword : keywords)
|
||||||
|
if(str == keyword.name)
|
||||||
|
return true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_string_literal(const std::string& str)
|
||||||
|
{
|
||||||
|
if(str[0] == '#')
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_decimal_literal(const std::string& str)
|
||||||
|
{
|
||||||
|
for(const char &c : str)
|
||||||
|
if(!std::isdigit(c) && c != '.')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_identifier(const std::string& str)
|
||||||
|
{
|
||||||
|
for(const char& c : str)
|
||||||
|
if(!(std::isalpha(c) || c == '_'))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Token::parse_as_keyword(const std::string &str)
|
||||||
|
{
|
||||||
|
if(!is_keyword(str))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
type = TokenType::KEYWORD;
|
||||||
|
val_string = str;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Token::parse_as_literal(const std::string &str)
|
||||||
|
{
|
||||||
|
if(is_string_literal(str))
|
||||||
|
{
|
||||||
|
type = TokenType::LITERAL;
|
||||||
|
literal_type = ValueType::STRING;
|
||||||
|
auto str_copy = str;
|
||||||
|
str_copy.erase(0, 1);
|
||||||
|
val_string = str_copy;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if(is_decimal_literal(str))
|
||||||
|
{
|
||||||
|
type = TokenType::LITERAL;
|
||||||
|
literal_type = ValueType::DECIMAL;
|
||||||
|
val_float = std::stof(str);
|
||||||
|
val_string = str;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Token::parse_as_identifier(const std::string &str)
|
||||||
|
{
|
||||||
|
if(is_identifier(str))
|
||||||
|
{
|
||||||
|
type = TokenType::IDENTIFIER;
|
||||||
|
val_string = str;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Token::Token(const std::string &str)
|
||||||
|
{
|
||||||
|
if (parse_as_keyword(str));
|
||||||
|
else if(parse_as_literal(str));
|
||||||
|
else if(parse_as_identifier(str));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw MalformedIdentifierExcept(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Token::print() const
|
||||||
|
{
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
|
case TokenType::IDENTIFIER:
|
||||||
|
std::cout << "Identifier: \"" << val_string << "\"";
|
||||||
|
break;
|
||||||
|
case TokenType::KEYWORD:
|
||||||
|
std::cout << "Keyword: \"" << val_string << "\"";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TokenType::LITERAL:
|
||||||
|
std::cout << "Literal of type ";
|
||||||
|
if(literal_type == ValueType::DECIMAL)
|
||||||
|
std::cout << "decimal: " << val_float;
|
||||||
|
else if(literal_type == ValueType::STRING)
|
||||||
|
std::cout << "string: \"" << val_string << "\"";
|
||||||
|
break;
|
||||||
|
case TokenType::ID_OR_LIT:
|
||||||
|
std::cerr << "Identifier or Literal?! Something went terribly wrong!!";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Instruction::Instruction(std::vector<Token>& _token_list)
|
||||||
|
{
|
||||||
|
tokens = std::move(_token_list);
|
||||||
|
|
||||||
|
// resolve our keyword
|
||||||
|
auto keyword_it = std::find(keywords.begin(), keywords.end(), tokens[0].val_string);
|
||||||
|
|
||||||
|
// Throw if unknown
|
||||||
|
if(keyword_it == keywords.end())
|
||||||
|
throw UnknownKeywordExcept(tokens[0].val_string);
|
||||||
|
else
|
||||||
|
keyword_ptr = &*keyword_it;
|
||||||
|
|
||||||
|
// Make sure the keyword gets the number of arguments it needs
|
||||||
|
if(keyword_ptr->expected_num_args != -1 && (keyword_ptr->expected_num_args != tokens.size() - 1))
|
||||||
|
throw WrongArgumentCountExcept(keyword_ptr->name, keyword_ptr->expected_num_args, tokens.size() - 1);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
94
src/parse.hpp
Normal file
94
src/parse.hpp
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
#ifndef BISCUIT_PARSE_HPP_INCLUDED
|
||||||
|
#define BISCUIT_PARSE_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include "keywords.hpp"
|
||||||
|
|
||||||
|
enum TokenType
|
||||||
|
{
|
||||||
|
KEYWORD,
|
||||||
|
IDENTIFIER,
|
||||||
|
LITERAL,
|
||||||
|
ID_OR_LIT
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ValueType
|
||||||
|
{
|
||||||
|
STRING,
|
||||||
|
DECIMAL,
|
||||||
|
ANY
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
WrongTokenExcept(std::string _name, const TokenType& _expected, const TokenType& _got)
|
||||||
|
: expected(_expected), got(_got), keyword_name(_name) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TypeErrorExcept : public std::exception
|
||||||
|
{
|
||||||
|
ValueType expected, got;
|
||||||
|
std::string keyword_name;
|
||||||
|
TypeErrorExcept(std::string _name, const ValueType& _expected, const ValueType& _got)
|
||||||
|
: expected(_expected), got(_got), keyword_name(_name) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct Token
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
bool parse_as_keyword(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
|
||||||
|
bool parse_as_identifier(const std::string &str);
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum TokenType type;
|
||||||
|
enum ValueType literal_type;
|
||||||
|
float val_float;
|
||||||
|
std::string val_string;
|
||||||
|
|
||||||
|
Token(const std::string &str);
|
||||||
|
|
||||||
|
void print() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Instruction
|
||||||
|
{
|
||||||
|
std::vector<Token> tokens;
|
||||||
|
Keyword *keyword_ptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Try to parse a list of symbols as instructions
|
||||||
|
Instruction(std::vector<Token>& _token_list);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
11
src/runtime.hpp
Normal file
11
src/runtime.hpp
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#ifndef BISCUIT_RUNTIME_HPP_INCLUDED
|
||||||
|
#define BISCUIT_RUNTIME_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
struct Context
|
||||||
|
{
|
||||||
|
std::vector<
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue