feature/read_file #13

Merged
cromer merged 6 commits from feature/read_file into develop 2023-02-13 23:04:38 -03:00
12 changed files with 203 additions and 66 deletions

1
.gitignore vendored
View File

@ -2,3 +2,4 @@
.vscode .vscode
builddir builddir
*.kb *.kb
*.obk

View File

@ -11,19 +11,20 @@ project('obelisk',
llvm = dependency('llvm', version: '>= 14.0.0', modules : ['core', 'target', 'mcjit', 'nativecodegen'], required : true, method: 'config-tool') llvm = dependency('llvm', version: '>= 14.0.0', modules : ['core', 'target', 'mcjit', 'nativecodegen'], required : true, method: 'config-tool')
doxygen = find_program('doxygen', required : false)
cdata = configuration_data() cdata = configuration_data()
cdata.set('VERSION', meson.project_version()) cdata.set('VERSION', meson.project_version())
if find_program('dot', required : false).found() docs_enabled = get_option('docs')
cdata.set('HAVE_DOT', 'YES') if docs_enabled
else doxygen = find_program('doxygen', required : false)
cdata.set('HAVE_DOT', 'NO') if doxygen.found()
endif if find_program('dot', required : false).found()
cdata.set('HAVE_DOT', 'YES')
if doxygen.found() else
subdir('doc') cdata.set('HAVE_DOT', 'NO')
endif
subdir('doc')
endif
endif endif
subdir('src') subdir('src')

5
meson_options.txt Normal file
View File

@ -0,0 +1,5 @@
option('docs',
type: 'boolean',
value: true,
description: 'Build documentation for obelisk'
)

View File

@ -2,20 +2,33 @@
#include <iostream> #include <iostream>
obelisk::Lexer::Lexer(const std::string& sourceFile)
{
fileStream_.open(sourceFile, std::ifstream::in);
if (!fileStream_)
{
throw obelisk::LexerException("could not open source file " + sourceFile);
}
}
obelisk::Lexer::~Lexer()
{
fileStream_.close();
fileStream_.clear();
}
int obelisk::Lexer::getToken() int obelisk::Lexer::getToken()
{ {
static int lastChar = ' ';
while (isspace(lastChar)) while (isspace(lastChar))
{ {
lastChar = std::getc(stdin); lastChar = fileStream_.get();
} }
if (isalpha(lastChar)) if (isalpha(lastChar))
{ {
eraseIdentifier(); eraseIdentifier();
appendIdentifier(lastChar); appendIdentifier(lastChar);
while (isalnum((lastChar = getchar()))) while (isalnum((lastChar = fileStream_.get())))
{ {
appendIdentifier(lastChar); appendIdentifier(lastChar);
} }
@ -63,7 +76,7 @@ int obelisk::Lexer::getToken()
firstPeriod = true; firstPeriod = true;
} }
numberStr += lastChar; numberStr += lastChar;
lastChar = getchar(); lastChar = fileStream_.get();
} }
while (isdigit(lastChar) || lastChar == '.'); while (isdigit(lastChar) || lastChar == '.');
@ -83,7 +96,7 @@ int obelisk::Lexer::getToken()
} }
else if (lastChar == '/') else if (lastChar == '/')
{ {
lastChar = getchar(); lastChar = fileStream_.get();
if (lastChar == '/') if (lastChar == '/')
{ {
commentLine(&lastChar); commentLine(&lastChar);
@ -101,7 +114,7 @@ int obelisk::Lexer::getToken()
} }
int thisChar = lastChar; int thisChar = lastChar;
lastChar = getchar(); lastChar = fileStream_.get();
return thisChar; return thisChar;
} }
@ -109,7 +122,7 @@ void obelisk::Lexer::commentLine(int* lastChar)
{ {
do do
{ {
*lastChar = getchar(); *lastChar = fileStream_.get();
} }
while (*lastChar != EOF && *lastChar != '\n' && *lastChar != '\r'); while (*lastChar != EOF && *lastChar != '\n' && *lastChar != '\r');
} }

View File

@ -1,6 +1,7 @@
#ifndef OBELISK_LEXER_H #ifndef OBELISK_LEXER_H
#define OBELISK_LEXER_H #define OBELISK_LEXER_H
#include <fstream>
#include <string> #include <string>
namespace obelisk namespace obelisk
@ -12,6 +13,12 @@ namespace obelisk
class Lexer class Lexer
{ {
private: private:
int lastChar = ' ';
/**
* @brief The stream of the source file being read.
*
*/
std::ifstream fileStream_;
/** /**
* @brief The last found identifier. * @brief The last found identifier.
* *
@ -21,7 +28,7 @@ namespace obelisk
* @brief The last found number. * @brief The last found number.
* *
*/ */
double numberValue_; double numberValue_ = 0;
/** /**
* @brief Set the identifier. * @brief Set the identifier.
@ -113,6 +120,19 @@ namespace obelisk
kTokenString = -9 kTokenString = -9
}; };
/**
* @brief Construct a new Lexer object.
*
* @param[in] sourceFile The source file to read.
*/
Lexer(const std::string& sourceFile);
/**
* @brief Destroy the Lexer object.
*
*/
~Lexer();
/** /**
* @brief Gets the next token in the source code. * @brief Gets the next token in the source code.
* *

View File

@ -1,3 +1,10 @@
conf_data = configuration_data()
conf_data.set('version', meson.project_version())
configure_file(input : 'version.h.in',
output : 'version.h',
configuration : conf_data
)
obelisk_sources = files( obelisk_sources = files(
'obelisk.cpp', 'obelisk.cpp',
'lexer.cpp', 'lexer.cpp',

View File

@ -7,8 +7,8 @@ const char* obelisk::Fact::createTable()
CREATE TABLE "fact" ( CREATE TABLE "fact" (
"id" INTEGER NOT NULL UNIQUE, "id" INTEGER NOT NULL UNIQUE,
"left_entity" INTEGER NOT NULL, "left_entity" INTEGER NOT NULL,
"right_entity" INTEGER NOT NULL,
"verb" INTEGER NOT NULL, "verb" INTEGER NOT NULL,
"right_entity" INTEGER NOT NULL,
"is_true" INTEGER NOT NULL DEFAULT 0, "is_true" INTEGER NOT NULL DEFAULT 0,
PRIMARY KEY("id" AUTOINCREMENT), PRIMARY KEY("id" AUTOINCREMENT),
UNIQUE("left_entity", "right_entity", "verb") UNIQUE("left_entity", "right_entity", "verb")

View File

@ -2,20 +2,20 @@
#include "lexer.h" #include "lexer.h"
#include "obelisk.h" #include "obelisk.h"
#include "parser.h" #include "parser.h"
#include "version.h"
#include <iomanip> #include <iomanip>
#include <iostream> #include <iostream>
#include <limits> #include <limits>
#include <memory> #include <memory>
static int obelisk::mainLoop() int obelisk::mainLoop(const std::vector<std::string>& sourceFiles, const std::string& kbFile)
{ {
auto parser = std::unique_ptr<obelisk::Parser> {new obelisk::Parser()};
std::unique_ptr<obelisk::KnowledgeBase> kb; std::unique_ptr<obelisk::KnowledgeBase> kb;
try try
{ {
kb = std::unique_ptr<obelisk::KnowledgeBase> {new obelisk::KnowledgeBase("cromer.kb")}; kb = std::unique_ptr<obelisk::KnowledgeBase> {new obelisk::KnowledgeBase(kbFile.c_str())};
} }
catch (obelisk::KnowledgeBaseException& exception) catch (obelisk::KnowledgeBaseException& exception)
{ {
@ -23,8 +23,20 @@ static int obelisk::mainLoop()
return EXIT_FAILURE; return EXIT_FAILURE;
} }
// Prime the first token. size_t file = 0;
fprintf(stderr, "ready> "); std::shared_ptr<obelisk::Lexer> lexer;
try
{
lexer = std::shared_ptr<obelisk::Lexer> {new obelisk::Lexer(sourceFiles[file++])};
}
catch (obelisk::LexerException& exception)
{
std::cout << exception.what() << std::endl;
return EXIT_FAILURE;
}
auto parser = std::unique_ptr<obelisk::Parser> {new obelisk::Parser(lexer)};
// prime the first token
try try
{ {
parser->getNextToken(); parser->getNextToken();
@ -37,14 +49,29 @@ static int obelisk::mainLoop()
while (true) while (true)
{ {
fprintf(stderr, "ready> ");
switch (parser->getCurrentToken()) switch (parser->getCurrentToken())
{ {
case obelisk::Lexer::kTokenEof : case obelisk::Lexer::kTokenEof :
return EXIT_SUCCESS; // end of source file found, create a new lexer and pass it to the parser to use
case ';' : // ignore top-level semicolons. if (file >= sourceFiles.size())
std::cout << "Identifier: " << parser->getLexer()->getIdentifier() << std::endl; {
std::cout << "Num: " << parser->getLexer()->getNumberValue() << std::endl; return EXIT_SUCCESS;
}
try
{
lexer = std::shared_ptr<obelisk::Lexer> {new obelisk::Lexer(sourceFiles[file++])};
parser->setLexer(lexer);
// prime the first token in the parser
parser->getNextToken();
}
catch (obelisk::LexerException& exception)
{
std::cout << exception.what() << std::endl;
return EXIT_FAILURE;
}
break;
case ';' :
// semicolon found, the end of a statement
try try
{ {
parser->getNextToken(); parser->getNextToken();
@ -73,38 +100,57 @@ static int obelisk::mainLoop()
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
static void obelisk::showUsage()
{
std::cout << obelisk::usageMessage << std::endl;
}
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
for (int i = 1; i < argc; i++) std::vector<std::string> sourceFiles;
std::string kbFile = "obelisk.kb";
while (true)
{ {
std::cout << argv[i] << std::endl; int option_index = 0;
switch (getopt_long(argc, argv, "k:hv", obelisk::long_options, &option_index))
{
case 'k' :
kbFile = std::string(optarg);
continue;
case 'h' :
obelisk::showUsage();
return EXIT_SUCCESS;
break;
case 'v' :
std::cout << "obelisk " << obelisk::version << std::endl;
return EXIT_SUCCESS;
break;
default :
obelisk::showUsage();
return EXIT_FAILURE;
break;
case -1 :
break;
}
break;
} }
// This can be used to store a double as 2 floats in the database, then restore it back to a double. if (optind < argc)
// Inspired by Godot's double precision on the GPU to render large worlds.
/*try
{ {
float first; while (optind < argc)
float second; {
double var = 0.123456789012345; sourceFiles.push_back(argv[optind++]);
}
obelisk::KnowledgeBase* kb = new obelisk::KnowledgeBase("cromer.kb");
kb->getFloat(first, second, var);
std::cout << std::setprecision(std::numeric_limits<double>::digits10)
<< "Double: " << var << std::endl
<< "First: " << first << std::endl
<< "Second: " << second << std::endl;
var = 0.0;
kb->getDouble(var, first, second);
std::cout << std::setprecision(std::numeric_limits<double>::digits10)
<< "Double: " << var << std::endl
<< "First: " << first << std::endl
<< "Second: " << second << std::endl;
} }
catch (obelisk::KnowledgeBaseException& exception)
if (sourceFiles.size() == 0)
{ {
obelisk::showUsage();
return EXIT_FAILURE; return EXIT_FAILURE;
}*/ }
return obelisk::mainLoop(); return obelisk::mainLoop(sourceFiles, kbFile);
} }

View File

@ -1,15 +1,46 @@
#include <getopt.h>
/** /**
* @brief The obelisk namespace contains everything needed to compile obelisk * @brief The obelisk namespace contains everything needed to compile obelisk.
* code. * code.
* *
*/ */
namespace obelisk namespace obelisk
{ {
/**
* @brief The usage messsage displayed during help or incorrect usage.
*
*/
std::string usageMessage = R"(Usage: obelisk [OPTION]... [FILE]...
Compile the obelisk source FILE(s) into knoweldge base and library.
Options:
-h, --help shows this help/usage message
-k, --kb=FILENAME output knowldege base filename
-v, --version shows the version of obelisk)";
/**
* @brief The command line arguments that obelisk accepts.
*
*/
static struct option long_options[] = {
{"help", no_argument, 0, 'h'},
{"kb", required_argument, 0, 'k'},
{"version", no_argument, 0, 'v'},
{0, 0, 0, 0 }
};
/**
* @brief Prints out the usage of obelisk to the stdin.
*
*/
static void showUsage();
/** /**
* @brief This is the main loop for obelisk. * @brief This is the main loop for obelisk.
* This loop handles lexing and parsing of obelisk source code. * This loop handles lexing and parsing of obelisk source code.
* *
* @return int Returns EXIT_SUCCESS or EXIT_FAILURE. * @return int Returns EXIT_SUCCESS or EXIT_FAILURE.
*/ */
static int mainLoop(); int mainLoop(const std::vector<std::string> &sourceFiles, const std::string &kbFile);
} // namespace obelisk } // namespace obelisk

View File

@ -11,16 +11,17 @@
#include <string> #include <string>
#include <vector> #include <vector>
obelisk::Parser::Parser() std::shared_ptr<obelisk::Lexer> obelisk::Parser::getLexer()
{
lexer_ = std::unique_ptr<obelisk::Lexer> {new obelisk::Lexer()};
}
std::unique_ptr<obelisk::Lexer>& obelisk::Parser::getLexer()
{ {
return lexer_; return lexer_;
} }
void obelisk::Parser::setLexer(std::shared_ptr<obelisk::Lexer> lexer)
{
lexer_ = lexer;
currentToken_ = 0;
}
int obelisk::Parser::getNextToken() int obelisk::Parser::getNextToken()
{ {
try try

View File

@ -15,8 +15,8 @@ namespace obelisk
class Parser class Parser
{ {
private: private:
std::unique_ptr<obelisk::Lexer> lexer_; std::shared_ptr<obelisk::Lexer> lexer_;
int currentToken_; int currentToken_ = 0;
void setCurrentToken(int currentToken); void setCurrentToken(int currentToken);
@ -37,9 +37,13 @@ namespace obelisk
void parseFact(std::vector<obelisk::Fact>& facts); void parseFact(std::vector<obelisk::Fact>& facts);
public: public:
Parser(); Parser(std::shared_ptr<obelisk::Lexer> lexer) :
lexer_(lexer)
{
}
std::unique_ptr<obelisk::Lexer>& getLexer(); std::shared_ptr<obelisk::Lexer> getLexer();
void setLexer(std::shared_ptr<obelisk::Lexer> lexer);
int getCurrentToken(); int getCurrentToken();

8
src/version.h.in Normal file
View File

@ -0,0 +1,8 @@
namespace obelisk
{
/**
* @brief The current version of obelisk.
*
*/
std::string version = "@version@";
} // namespace obelisk