This commit is contained in:
2024-11-14 14:39:09 -05:00
parent 427eb56a50
commit 020bd3a5db
11 changed files with 1131 additions and 3 deletions

83
sub/xpat/src/atoms.rs Normal file
View File

@@ -0,0 +1,83 @@
pub type Pattern<'l> = &'l[Atom];
/// Pattern atoms.
///
/// The scanner will silently ignore nonsensical arguments.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Atom {
/// Matches a single byte.
Byte(u8),
/// Captures the cursor in the save array at the specified index.
Save(u8),
/// After a Pop later continue matching at the current cursor plus the argument.
Push(u8),
/// Pops the cursor from the stack and continues matching.
Pop,
/// Sets a mask to apply on next byte match.
Fuzzy(u8),
/// Skips a fixed number of bytes.
Skip(u8),
/// Rewinds the cursor a fixed number of bytes.
Back(u8),
/// Extends the push, skip, back and many range by `argument * 256`.
Rangext(u8),
/// Looks for the next pattern at most a certain number of bytes ahead.
Many(u8),
/// Follows a signed 1 byte jump.
///
/// Reads the byte under the cursor, sign extends it, adds it plus 1 to the cursor and continues matching.
Jump1,
/// Follows a signed 4 byte jump.
///
/// Reads the dword under the cursor and adds it plus 4 to the cursor and continues matching.
Jump4,
/// Follows an absolute pointer.
///
/// Reads the pointer under the cursor, translates it to an RVA, assigns it to the cursor and continues matching.
///
/// Matching fails immediately when translation to an RVA fails.
Ptr,
/// Follows a position independent reference.
///
/// Reads the dword under the cursor and adds it to the saved cursor for the given slot and continues matching.
Pir(u8),
/// Compares the cursor with the value in the given save slot and fails if they're not equal.
Check(u8),
/// Checks if the cursor is aligned to `(1 << value)`.
Aligned(u8),
/// Reads and sign-extends the byte under the cursor, writes to the given slot and advances the cursor by 1.
ReadI8(u8),
/// Reads and zero-extends the byte under the cursor, writes to the given slot and advances the cursor by 1.
ReadU8(u8),
/// Reads and sign-extends the word under the cursor, writes to the given slot and advances the cursor by 2.
ReadI16(u8),
/// Reads and zero-extends the word under the cursor, writes to the given slot and advances the cursor by 2.
ReadU16(u8),
/// Reads the dword under the cursor, writes to the given slot and advances the cursor by 4.
ReadI32(u8),
/// Reads the dword under the cursor, writes to the given slot and advances the cursor by 4.
ReadU32(u8),
/// Writes zero to the given save slot.
Zero(u8),
/// Sets a retry point when matching fails.
///
/// When matching fails the cursor is restored and matching begins again skipping _N_ atoms.
Case(u8),
/// Continues matching after a case atom, skipping the next _N_ atoms.
Break(u8),
/// Null instruction, used to make the parser easier to write.
Nop,
}
impl Atom {
pub fn save_len(pat: &[Atom]) -> usize {
pat.iter().filter_map(|&atom| {
match atom {
Atom::Save(slot) | Atom::Pir(slot) | Atom::Check(slot) | Atom::Zero(slot) |
Atom::ReadI8(slot) | Atom::ReadI16(slot) | Atom::ReadI32(slot) |
Atom::ReadU8(slot) | Atom::ReadU16(slot)| Atom::ReadU32(slot) => Some(slot as usize + 1),
_ => None,
}
}).max().unwrap_or(0)
}
}