89 lines
2.5 KiB
C++
89 lines
2.5 KiB
C++
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <optional>
|
|
#include <regex.h>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
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<Address> firstAddress;
|
|
std::optional<Address> 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> substitute;
|
|
std::optional<Translate> 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<Command> commands;
|
|
};
|
|
|
|
} // namespace sedpp
|