Initial commit

This commit is contained in:
2024-12-02 06:30:40 +00:00
commit fd62fb822d
33 changed files with 1972 additions and 0 deletions

46
include/ast/ast.hpp Normal file
View File

@ -0,0 +1,46 @@
/*
* Fsh Grammar
*
* Command_Line ::= Command EOF
* | Command Pipeline_Command
*
* Pipeline_Command ::= "|" Command EOF
* | "|" Command "|" Pipeline_Command
*
* Command ::= Command_Name [Flag_Opt] {Command_Argument} [Redirect]
*
* Redirects ::= [LRedirect Word] RRedirect Word | [RRedirect Word] LRedirect Word
*
* Command_Argument ::= Word | String_Literal
*
* Command_Name ::= Word
*/
#pragma once
#include "lexer.hpp"
#include "util/text.hpp"
#include "ast/ast_base.hpp"
#include "ast/ast_token.hpp"
#include "ast/ast_component.hpp"
#include "ast/ast_executable.hpp"
namespace fsh {
class AstFactory {
public:
// Generates an abstract syntax tree
static std::shared_ptr<ExecutableNode> generate_ast(std::list<Token>& list) {
auto it = list.begin();
return CommandLineNode::build(it);
}
private:
static AstFactory& get_factory();
AstFactory() {}
AstFactory(const AstFactory&) = default;
};
}

67
include/ast/ast_base.hpp Normal file
View File

@ -0,0 +1,67 @@
#pragma once
#include <string>
#include <memory>
#include <stdexcept>
#include <sstream>
#include "lexer.hpp"
#include "util/text.hpp"
namespace fsh {
enum NodeType {
COMMAND_LINE,
COMMAND,
PIPELINE_COMMAND,
LREDIRECTS,
RREDIRECTS,
REDIRECTS,
STRING_LITERAL,
COMMAND_ARGUMENT,
TOKEN
};
class AstNode {
friend class std::shared_ptr<AstNode>;
public:
NodeType gtype() {return type;}
const std::string& gname() {return name;};
protected:
using TokenType = Lexer::TokenType;
AstNode(NodeType type, std::string name) : type(type), name(name) {}
template <class T>
static std::shared_ptr<T> Optional(std::list<Token>::iterator& it, std::shared_ptr<T>& node_ptr);
template <class T>
static std::shared_ptr<T> Optional(std::list<Token>::iterator& it) {
std::shared_ptr<T> node_ptr;
return Optional<T>(it, node_ptr);
}
template <class T>
static std::shared_ptr<T> Mandatory(std::list<Token>::iterator& it) {return T::build(it);}
private:
AstNode();
AstNode(const AstNode&);
NodeType type;
const std::string name;
};
class ExecutableNode : public AstNode {
public:
virtual void print(int indent) {};
virtual void execute(std::istream &in, std::ostream &out) {}
protected:
ExecutableNode(NodeType type, std::string Name) : AstNode(type, Name) {}
private:
};
class AstBuildError : public std::runtime_error {
public:
AstBuildError(std::string err) : std::runtime_error(err) {}
};
}

View File

@ -0,0 +1,90 @@
#pragma once
#include <memory>
#include <optional>
#include "ast/ast_base.hpp"
#include "ast_token.hpp"
#include "lexer.hpp"
#include "util/text.hpp"
namespace fsh {
class CommandArgumentNode : public AstNode {
public:
static std::shared_ptr<CommandArgumentNode> build(std::list<Token>::iterator& it);
Lexer::TokenType gtoken_type() {return type;}
std::string& gvalue() {return value;}
protected:
CommandArgumentNode(TokenNode<TokenType::WORD>::shared word)
: AstNode(NodeType::COMMAND_ARGUMENT, "StringArgument"),
type(word->gtoken_type()),
value(word->gvalue()) {}
CommandArgumentNode(TokenNode<TokenType::STRING_LITERAL>::shared word)
: AstNode(NodeType::COMMAND_ARGUMENT, "StringArgument"),
type(word->gtoken_type()),
value(word->gvalue()) {}
private:
Lexer::TokenType type;
std::string value;
};
class LRedirectNode : public AstNode {
public:
static std::shared_ptr<LRedirectNode> build(std::list<Token>::iterator& it);
std::string gvalue() {return input;}
protected:
LRedirectNode(TokenNode<TokenType::LREDIRECTION>::shared, TokenNode<TokenType::WORD>::shared in)
: AstNode(NodeType::LREDIRECTS, "LRedirectNode"),
input(in->gvalue()) {}
private:
std::string input;
};
class RRedirectNode : public AstNode {
public:
static std::shared_ptr<RRedirectNode> build(std::list<Token>::iterator& it);
std::string gvalue() {return output;}
bool gappend() {return append;}
protected:
RRedirectNode(TokenNode<TokenType::RREDIRECTION>::shared rr, TokenNode<TokenType::WORD>::shared out)
: AstNode(NodeType::RREDIRECTS, "LRedirectNode"),
output(out->gvalue()),
append(rr->gvalue().size()>1) {}
private:
std::string output;
bool append;
};
class RedirectsNode : public AstNode {
public:
static std::shared_ptr<RedirectsNode> build(std::list<Token>::iterator& it);
std::optional<std::string> ginput() {return input;}
std::optional<std::string> goutput() {return output;}
bool gappend() {return append;}
protected:
RedirectsNode(std::shared_ptr<LRedirectNode> in, std::shared_ptr<RRedirectNode> out)
: AstNode(NodeType::REDIRECTS, "RedirectNode"),
input(util::mk_optional(in)),
output(util::mk_optional(out)) {if(out) append = out->gappend();}
private:
std::optional<std::string> input;
std::optional<std::string> output;
bool append = false;
};
}

View File

@ -0,0 +1,78 @@
#pragma once
#include <memory>
#include <stdexcept>
#include <optional>
#include "ast/ast_base.hpp"
#include "ast/ast_token.hpp"
#include "ast/ast_component.hpp"
#include "lexer.hpp"
#include "util/text.hpp"
namespace fsh {
class CommandNode : public ExecutableNode {
using ArgumentVec = std::vector<std::shared_ptr<CommandArgumentNode> >;
public:
static std::shared_ptr<CommandNode> build(std::list<Token>::iterator& it);
virtual void print(int indent) override;
virtual void execute(std::istream &in, std::ostream &out) override;
protected:
CommandNode(
TokenNode<TokenType::WORD>::shared cmd_name,
TokenNode<TokenType::FLAG>::shared flag,
ArgumentVec args,
std::shared_ptr<RedirectsNode> redirects
) : ExecutableNode(NodeType::COMMAND, "CommandNode"),
cmd_name(cmd_name->gvalue()),
flag(util::mk_optional(flag)),
redirects(redirects),
args(args) {}
private:
std::string cmd_name;
std::optional<std::string> flag;
std::shared_ptr<RedirectsNode> redirects;
ArgumentVec args;
};
class PipeLineNode : public ExecutableNode {
public:
static std::shared_ptr<PipeLineNode> build(std::list<Token>::iterator& it);
virtual void print(int indent) override;
virtual void execute(std::istream &in, std::ostream &out) override;
protected:
PipeLineNode(std::shared_ptr<CommandNode> l, std::shared_ptr<ExecutableNode> r)
: ExecutableNode(NodeType::PIPELINE_COMMAND, "PipeLine"),
l_command(l),
r_command(r) {}
private:
std::shared_ptr<ExecutableNode> l_command;
std::shared_ptr<ExecutableNode> r_command;
};
class CommandLineNode : public ExecutableNode {
public:
static std::shared_ptr<CommandLineNode> build(std::list<Token>::iterator& it);
virtual void print(int indent) override;
virtual void execute(std::istream &in, std::ostream &out) override;
protected:
CommandLineNode(std::shared_ptr<ExecutableNode> command, std::shared_ptr<ExecutableNode> pipe = nullptr)
: ExecutableNode(NodeType::COMMAND_LINE, "CommandLine"),
command(command),
pipe(pipe) {}
private:
std::shared_ptr<ExecutableNode> command;
std::shared_ptr<ExecutableNode> pipe;
};
}

26
include/ast/ast_token.hpp Normal file
View File

@ -0,0 +1,26 @@
#pragma once
#include <memory>
#include "ast/ast_base.hpp"
#include "util/text.hpp"
namespace fsh {
template<Lexer::TokenType T>
class TokenNode : public AstNode {
public:
using shared = std::shared_ptr<TokenNode>;
Lexer::TokenType gtoken_type() {return T;}
std::string& gvalue() {return value;};
static std::shared_ptr<TokenNode> build(std::list<Token>::iterator& it);
protected:
TokenNode(std::string value)
: AstNode(NodeType::TOKEN, util::tokens[T]), value(value) {}
private:
std::string value;
};
}