#pragma once #ifndef PARSODUS_GRAMMAR_H #include "Parsodus/util/firstset.h" #include "Parsodus/util/followset.h" #include #include #include #include #include #include namespace pds { enum class PrecedenceType { LEFT, RIGHT, NONASSOC }; /** * Represents a grammar rule * head -> tail[0] tail[1] ... tail[tail.size() - 1] */ struct Rule { std::string head; ///< The replaced variable std::vector tail; ///< The replacement rule const std::string name; ///< An optional name for this rule, if it's empty, there's no name std::pair> precedence; ///< precedence for this rule, the bool indicates whether it's valid (invalid if there is no rightmost terminal and no explicit precedence) bool operator<(const Rule& other) const { if(head != other.head){ return head < other.head; } else { return tail < other.tail; } } Rule() : Rule("", {}, ""){} Rule(const std::string& h, const std::vector& t) : Rule(h, t, "") {} Rule(const std::string& h, const std::vector& t, const std::string& name) : head(h), tail(t), name(name), precedence{false, {0, PrecedenceType::RIGHT}} {} Rule(const std::string& h, const std::vector& t, const std::string& name, std::pair precedence) : head(h), tail(t), name(name), precedence{true, precedence} {} }; /** * A context free grammar * Keeps track of variables, terminals and replacement rules */ struct Grammar { std::string start; ///< the starting variable std::set variables; ///< the variables std::set terminals; ///< the terminals std::deque> rules; ///< the replacement rules std::map > precedence; ///< higher value -> higher precedence std::unique_ptr first; std::unique_ptr follow; Grammar() : start(""), variables(), terminals(), rules(), precedence(), first(nullptr), follow(nullptr) {} Grammar(const Grammar& rhs) : start(rhs.start), variables(rhs.variables), terminals(rhs.terminals) , rules(rhs.rules), precedence(rhs.precedence), first(nullptr), follow(nullptr) { if (rhs.first) first = std::make_unique(*rhs.first); if (rhs.follow) follow = std::make_unique(*rhs.follow); } }; } #endif //PARSODUS_GRAMMAR_H