You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
119 lines
3.1 KiB
119 lines
3.1 KiB
//
|
|
// Created by lenfrex on 2023/5/7.
|
|
//
|
|
|
|
#ifndef LEXER_CPP_GRAMMAR_H
|
|
#define LEXER_CPP_GRAMMAR_H
|
|
|
|
#include <ostream>
|
|
#include "vector"
|
|
#include "string"
|
|
#include "set"
|
|
#include "map"
|
|
|
|
typedef std::string Express;
|
|
|
|
// 单个产生式的select集合
|
|
typedef std::pair<Express, std::set<char>> ExpressSelectSet;
|
|
|
|
// 多个产生式的Select集合set,同一个非终止符的所有推导式的select集合
|
|
typedef std::set<ExpressSelectSet> SelectSet;
|
|
|
|
typedef std::map<char, std::string> TableRow;
|
|
|
|
// 文法定义
|
|
class Grammar {
|
|
private:
|
|
|
|
char startChar;
|
|
|
|
// 非终止符,vn
|
|
std::set<char> nonTerminals = std::set<char>();;
|
|
|
|
// 终止符,vt
|
|
std::set<char> terminals = std::set<char>();;
|
|
|
|
// 文法产生式
|
|
std::map<char, std::set<Express>> productionsMap;
|
|
|
|
std::map<char, std::set<char>> firstSet = std::map<char, std::set<char>>();
|
|
std::map<char, std::set<char>> followSet = std::map<char, std::set<char>>();
|
|
std::map<char, SelectSet> selectSet = std::map<char, SelectSet>();
|
|
|
|
std::map<char, TableRow> analysisTable = std::map<char, std::map<char, std::string>>();
|
|
|
|
bool ll1Grammar = false;
|
|
|
|
void calcFirstSetForNonTerminal(char nonTerminal);
|
|
|
|
// 计算first集合
|
|
void generateFirstSet();
|
|
|
|
// 获取当前总的follow集合元素数量
|
|
int getTotalFollowSize();
|
|
|
|
// 计算follow集合
|
|
void generateFollowSet();
|
|
|
|
// follow集合预处理
|
|
void followPreProcess();
|
|
|
|
// follow集合完善处理
|
|
void followFinalProcess();
|
|
|
|
// 计算select集合
|
|
void generateSelectSet();
|
|
|
|
// 检查当前是否为LL1文法
|
|
bool isLL1Grammar();
|
|
|
|
// 构建预测分析表
|
|
void buildAnalysisTable();
|
|
|
|
public:
|
|
[[nodiscard]] const std::set<char> &getNonTerminals() const;
|
|
|
|
[[nodiscard]] const std::set<char> &getTerminals() const;
|
|
|
|
[[nodiscard]] const std::map<char, std::set<Express>> &getGrammarExpresses() const;
|
|
|
|
Grammar(const std::string &nonTerminalString, const std::string &terminalString,
|
|
const std::set<std::string> &productionTexts, char startChar);
|
|
|
|
[[nodiscard]] char getStartChar() const;
|
|
|
|
[[nodiscard]] const std::map<char, std::set<Express>> &getProductionsMap() const;
|
|
|
|
[[nodiscard]] const std::map<char, std::set<char>> &getFirstSet() const;
|
|
|
|
[[nodiscard]] const std::map<char, std::set<char>> &getFollowSet() const;
|
|
|
|
[[nodiscard]] const std::map<char, SelectSet> &getSelectSet() const;
|
|
|
|
[[nodiscard]] const std::map<char, TableRow> &getAnalysisTable() const;
|
|
|
|
[[nodiscard]] bool isLl1Grammar() const;
|
|
|
|
friend std::ostream &operator<<(std::ostream &os, const Grammar &grammar);
|
|
|
|
static bool canDeducedEmpty(const std::set<std::string> &productions);
|
|
};
|
|
|
|
// 文法不支持异常
|
|
class NotSupportedGrammarException : public std::exception {
|
|
private:
|
|
const std::string msg;
|
|
public:
|
|
[[nodiscard]] const char *what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_NOTHROW override {
|
|
return msg.data();
|
|
};
|
|
|
|
public:
|
|
explicit NotSupportedGrammarException(std::string msg) : msg(std::move(msg)) {};
|
|
|
|
[[nodiscard]] const std::string &getMsg() const {
|
|
return msg;
|
|
};
|
|
};
|
|
|
|
#endif //LEXER_CPP_GRAMMAR_H
|
|
|