90 lines
2.5 KiB
C++
90 lines
2.5 KiB
C++
#pragma once
|
|
|
|
#include <functional>
|
|
#include <list>
|
|
#include <string>
|
|
|
|
namespace fsh {
|
|
|
|
class Lexer {
|
|
public:
|
|
enum TokenType {
|
|
WHITESPACE,
|
|
WORD,
|
|
STRING_LITERAL,
|
|
OPT,
|
|
FLAG,
|
|
LREDIRECTION,
|
|
RREDIRECTION,
|
|
PIPE,
|
|
|
|
END_OF_STREAM
|
|
};
|
|
|
|
using Token = std::pair<Lexer::TokenType, std::string>;
|
|
|
|
int peek();
|
|
int consume();
|
|
Token next_token();
|
|
|
|
static std::list<Token> process(std::string line);
|
|
|
|
private:
|
|
std::string workspace;
|
|
unsigned int idx;
|
|
|
|
Lexer(std::string str) : workspace(str), idx(0) {}
|
|
};
|
|
using Token = Lexer::Token;
|
|
|
|
class LexerStateMachine {
|
|
friend class Lexer;
|
|
|
|
private:
|
|
enum State {
|
|
START,
|
|
REDIRECT,
|
|
FLAG_OPT,
|
|
POTENTIAL_WORD,
|
|
STRING_LITERAL,
|
|
STATE_COUNT,
|
|
|
|
END
|
|
};
|
|
|
|
using StateHandler = std::function<State(void)>;
|
|
|
|
Lexer& parser;
|
|
std::string token;
|
|
Lexer::TokenType type;
|
|
std::vector<StateHandler> state_handlers;
|
|
|
|
LexerStateMachine(Lexer& parser) :
|
|
parser(parser), token(""), type(Lexer::TokenType::WHITESPACE), state_handlers(STATE_COUNT) {
|
|
state_handlers[State::START] = std::bind(&LexerStateMachine::handle_start, this);
|
|
state_handlers[State::REDIRECT] = std::bind(&LexerStateMachine::handle_redirect, this);
|
|
state_handlers[State::FLAG_OPT] = std::bind(&LexerStateMachine::handle_flag_opt, this);
|
|
state_handlers[State::POTENTIAL_WORD] = std::bind(&LexerStateMachine::handle_potential_word, this);
|
|
state_handlers[State::STRING_LITERAL] = std::bind(&LexerStateMachine::handle_string_literal, this);
|
|
}
|
|
|
|
State set_type(Lexer::TokenType type, State state);
|
|
|
|
Token run();
|
|
|
|
State handle_start();
|
|
State handle_redirect();
|
|
State handle_flag_opt();
|
|
State handle_potential_word();
|
|
State handle_string_literal();
|
|
|
|
State word_like_handler(Lexer::TokenType type, State state);
|
|
};
|
|
|
|
inline LexerStateMachine::State LexerStateMachine::set_type(Lexer::TokenType type = Lexer::TokenType::WHITESPACE,
|
|
State state = State::END) {
|
|
this->type = type;
|
|
return state;
|
|
}
|
|
|
|
} // namespace fsh
|