develop #15
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,3 +2,4 @@
|
|||||||
.vscode
|
.vscode
|
||||||
builddir
|
builddir
|
||||||
*.kb
|
*.kb
|
||||||
|
*.obk
|
||||||
|
21
meson.build
21
meson.build
@ -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
5
meson_options.txt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
option('docs',
|
||||||
|
type: 'boolean',
|
||||||
|
value: true,
|
||||||
|
description: 'Build documentation for obelisk'
|
||||||
|
)
|
@ -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');
|
||||||
}
|
}
|
||||||
|
22
src/lexer.h
22
src/lexer.h
@ -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.
|
||||||
*
|
*
|
||||||
|
@ -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',
|
||||||
|
@ -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")
|
||||||
|
114
src/obelisk.cpp
114
src/obelisk.cpp
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
12
src/parser.h
12
src/parser.h
@ -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
8
src/version.h.in
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace obelisk
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief The current version of obelisk.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
std::string version = "@version@";
|
||||||
|
} // namespace obelisk
|
Loading…
Reference in New Issue
Block a user