| Server IP : 85.214.239.14 / Your IP : 216.73.216.212 Web Server : Apache/2.4.65 (Debian) System : Linux h2886529.stratoserver.net 4.9.0 #1 SMP Mon Sep 30 15:36:27 MSK 2024 x86_64 User : www-data ( 33) PHP Version : 8.2.29 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /proc/3/cwd/proc/3/task/3/root/usr/share/doc/re2c/examples/rust/state/ |
Upload File : |
/* Generated by re2c */
// re2rust $INPUT -o $OUTPUT -f
use std::fs::File;
use std::io::{Read, Write};
const DEBUG: bool = false;
macro_rules! log {
($($fmt:expr)? $(, $args:expr)*) => {
if DEBUG { println!($($fmt)? $(, $args)*) }
}
}
// Use a small buffer to cover the case when a lexeme doesn't fit.
// In real world use a larger buffer.
const BUFSIZE: usize = 10;
struct State {
file: File,
buf: [u8; BUFSIZE],
lim: usize,
cur: usize,
mar: usize,
tok: usize,
state: isize,
}
#[derive(Debug, PartialEq)]
enum Status {End, Ready, Waiting, BadPacket, BigPacket}
fn fill(st: &mut State) -> Status {
// Error: lexeme too long. In real life can reallocate a larger buffer.
if st.tok < 1 { return Status::BigPacket; }
// Shift buffer contents (discard everything up to the current lexeme).
st.buf.copy_within(st.tok..st.lim, 0);
st.lim -= st.tok;
st.cur -= st.tok;
st.mar = st.mar.overflowing_sub(st.tok).0; // underflows if marker is unused
st.tok = 0;
// Fill free space at the end of buffer with new data.
match st.file.read(&mut st.buf[st.lim..BUFSIZE - 1]) { // -1 for sentinel
Ok(n) => {
st.lim += n;
st.buf[st.lim] = 0; // append sentinel symbol
},
Err(why) => panic!("cannot read from file: {}", why)
}
return Status::Ready;
}
fn lex(st: &mut State, recv: &mut usize) -> Status {
let mut yych;
'lex: loop {
st.tok = st.cur;
let mut yystate : isize = st.state;
'yyl: loop {
match yystate {
-1 ..= 0 => {
yych = unsafe {*st.buf.get_unchecked(st.cur)};
match yych {
0x61 ..= 0x7A => {
st.cur += 1;
yystate = 3;
continue 'yyl;
}
_ => {
if st.cur >= st.lim {
st.state = 8;
return Status::Waiting;
}
st.cur += 1;
yystate = 1;
continue 'yyl;
}
}
}
1 => {
yystate = 2;
continue 'yyl;
}
2 => {
st.state = -1;
{ return Status::BadPacket; }
}
3 => {
st.mar = st.cur;
yych = unsafe {*st.buf.get_unchecked(st.cur)};
match yych {
0x3B => {
st.cur += 1;
yystate = 4;
continue 'yyl;
}
0x61 ..= 0x7A => {
st.cur += 1;
yystate = 5;
continue 'yyl;
}
_ => {
if st.cur >= st.lim {
st.state = 9;
return Status::Waiting;
}
yystate = 2;
continue 'yyl;
}
}
}
4 => {
st.state = -1;
{ *recv += 1; continue 'lex; }
}
5 => {
yych = unsafe {*st.buf.get_unchecked(st.cur)};
match yych {
0x3B => {
st.cur += 1;
yystate = 4;
continue 'yyl;
}
0x61 ..= 0x7A => {
st.cur += 1;
yystate = 5;
continue 'yyl;
}
_ => {
if st.cur >= st.lim {
st.state = 10;
return Status::Waiting;
}
yystate = 6;
continue 'yyl;
}
}
}
6 => {
st.cur = st.mar;
yystate = 2;
continue 'yyl;
}
7 => {
st.state = -1;
{ return Status::End; }
}
8 => {
if st.cur >= st.lim {
yystate = 7;
continue 'yyl;
}
yystate = 0;
continue 'yyl;
}
9 => {
if st.cur >= st.lim {
yystate = 2;
continue 'yyl;
}
yystate = 3;
continue 'yyl;
}
10 => {
if st.cur >= st.lim {
yystate = 6;
continue 'yyl;
}
yystate = 5;
continue 'yyl;
}
_ => {
panic!("internal lexer error")
}
}
}
}
}
fn test(packets: Vec<&[u8]>, expect: Status) {
// Create a "socket" (open the same file for reading and writing).
let fname = "pipe";
let mut fw: File = match File::create(fname) {
Err(why) => panic!("cannot open {}: {}", fname, why),
Ok(file) => file,
};
let fr: File = match File::open(fname) {
Err(why) => panic!("cannot read file {}: {}", fname, why),
Ok(file) => file,
};
// Initialize lexer state: `state` value is -1, all offsets are at the end
// of buffer, the character at `lim` offset is the sentinel (null).
let lim = BUFSIZE - 1;
let mut state = State {
file: fr,
// Sentinel (at `lim` offset) is set to null, which triggers YYFILL.
buf: [0; BUFSIZE],
cur: lim,
mar: lim,
tok: lim,
lim: lim,
state: -1,
};
// Main loop. The buffer contains incomplete data which appears packet by
// packet. When the lexer needs more input it saves its internal state and
// returns to the caller which should provide more input and resume lexing.
let mut status;
let mut send = 0;
let mut recv = 0;
loop {
status = lex(&mut state, &mut recv);
if status == Status::End {
log!("done: got {} packets", recv);
break;
} else if status == Status::Waiting {
log!("waiting...");
if send < packets.len() {
log!("sent packet {}", send);
match fw.write_all(packets[send]) {
Err(why) => panic!("cannot write to {}: {}", fname, why),
Ok(_) => send += 1,
}
}
status = fill(&mut state);
log!("queue: '{}'", String::from_utf8_lossy(&state.buf));
if status == Status::BigPacket {
log!("error: packet too big");
break;
}
assert_eq!(status, Status::Ready);
} else {
assert_eq!(status, Status::BadPacket);
log!("error: ill-formed packet");
break;
}
}
// Check results.
assert_eq!(status, expect);
if status == Status::End { assert_eq!(recv, send); }
// Cleanup: remove input file.
match std::fs::remove_file(fname) {
Err(why) => panic!("cannot remove {}: {}", fname, why),
Ok(_) => {}
}
}
fn main() {
test(vec![], Status::End);
test(vec![b"zero;", b"one;", b"two;", b"three;", b"four;"], Status::End);
test(vec![b"zer0;"], Status::BadPacket);
test(vec![b"goooooooooogle;"], Status::BigPacket);
}