#pragma once #include #include #include #include #include namespace sedpp { // Address kinds mirror GNU sed's address grammar. Step, Plus, and Modulo are // GNU extensions: FIRST~STEP as a standalone address, and +N/~N only as the // second half of a range. enum class AddressKind { None, Line, Last, Regex, Step, Plus, Modulo, }; // A parsed address keeps both the original text and numeric forms. The text is // still needed for special cases such as line address 0 and for empty regexes, // which mean "reuse the previous regular expression" at runtime. struct Address { AddressKind kind = AddressKind::None; std::string text; std::uint64_t first = 0; std::uint64_t second = 0; }; // Parsed state for the s command. flagOrder preserves p/e ordering because GNU // sed changes observable output depending on whether printing happens before or // after shell execution. struct Substitute { std::string pattern; std::string replacement; bool global = false; bool print = false; bool execute = false; bool ignoreCase = false; bool multiline = false; std::uint64_t occurrence = 0; std::string flagOrder; std::string writeFile; }; // y transliteration operates on decoded character strings, not regex syntax. struct Translate { std::string from; std::string to; }; // A compiled sed command. The opcode selects which optional payload is valid: // text for a/i/c/r/R/w/W/e, label for :/b/t/T, substitute for s, translate for y. struct Command { std::optional
firstAddress; std::optional
secondAddress; bool negate = false; char opcode = '\0'; // These fields are intentionally plain. sed commands are compact and varied; // a tiny tagged structure is easier to audit than a deep inheritance tree. std::string text; std::string label; std::optional substitute; std::optional translate; int exitCode = 0; int lineLength = 0; // Runtime range state. GNU sed keeps range activation per compiled command, // not globally, so the state lives with the command object. bool rangeActive = false; bool rangeJustStarted = false; std::uint64_t rangeCountdown = 0; bool zeroRangeStarted = false; }; // The compiler flattens the sed script into one vector. Braced blocks remain // explicit { and } opcodes so the runner can skip inactive blocks without a // second tree-shaped representation. struct Program { std::vector commands; }; } // namespace sedpp