我应该如何处理我的 BrainF**k 解释器中可能出现的否定?
How should I handle possible negatives in my BrainF**k interpreter?
我正在构建我的第一个解释器以更好地学习 Rust,我有点被这个问题困住了,因为我 tape/memory 是一个无符号 8 位整数的向量,但循环有时会导致底片。
我正在尝试在 BF 中执行这段代码(结果应该是“hello”):
+[----->+++<]>+.---.+++++++..+++.
我一直收到“试图减去溢出”的消息,因为第一个循环将位变为负数,当它注意到它是 0 时应该停止。
这是我的函数:
fn compile(code: Vec<Operations>) {
// Memory vector is of arbitrary length for now //
let mut memory: Vec<u8> = vec![0; 1000];
let mut mem_ptr = 0;
let mut code_ptr = 0;
let mut bracket_idx: Vec<usize> = Vec::new();
println!("{:?}", code);
while code_ptr < code.len() {
let command = code[code_ptr];
match command {
Operations::IncrementByte => memory[mem_ptr] += 1,
Operations::DecrementByte => memory[mem_ptr] -= 1,
Operations::IncrementPtr => mem_ptr += 1,
Operations::DecrementPtr => mem_ptr -= 1,
Operations::Read => log_ptr(&[memory[mem_ptr] as u8]),
Operations::StartLoop => bracket_idx.push(code_ptr),
Operations::EndLoop => {
if memory[mem_ptr] != 0 {
code_ptr = *bracket_idx.last().unwrap()
}
else {
bracket_idx.pop();
}
},
_ => println!("ERROR")
};
code_ptr += 1;
}
println!("{:?}", memory);
}
第一次进入循环时,当前值为1(因为循环前有一个+
)。在循环内,然后从该值中减去 5(因为有 5 个 -
)。因此,如果从 0 中减去导致溢出错误,则此程序将无法运行。
因此,要使该程序正常运行,您需要使用 wrapping_*
系列方法来环绕而不是在溢出时出现恐慌。
大多数整数运算以不同的形式存在:
carrying_*
(例如u8::carrying_u8
);
overflowing_*
(例如u8::overflowing_u8
);
saturating_*
(例如u8::saturating_u8
);
unchecked_*
(例如u8::unchecked_u8
);
wrapping_*
(例如u8::wrapping_u8
)。
这些中的每一个都允许对发生不足或溢出时发生的情况进行不同级别的控制。在这种情况下,您需要决定您希望您的应用程序做什么,并选择相关的方法。
还有包装器类型,例如 std::num::Wrapping
and std::num::Saturating
如果您始终希望所有操作都具有给定的行为,它会提供更简洁的语法。
我正在构建我的第一个解释器以更好地学习 Rust,我有点被这个问题困住了,因为我 tape/memory 是一个无符号 8 位整数的向量,但循环有时会导致底片。
我正在尝试在 BF 中执行这段代码(结果应该是“hello”):
+[----->+++<]>+.---.+++++++..+++.
我一直收到“试图减去溢出”的消息,因为第一个循环将位变为负数,当它注意到它是 0 时应该停止。
这是我的函数:
fn compile(code: Vec<Operations>) {
// Memory vector is of arbitrary length for now //
let mut memory: Vec<u8> = vec![0; 1000];
let mut mem_ptr = 0;
let mut code_ptr = 0;
let mut bracket_idx: Vec<usize> = Vec::new();
println!("{:?}", code);
while code_ptr < code.len() {
let command = code[code_ptr];
match command {
Operations::IncrementByte => memory[mem_ptr] += 1,
Operations::DecrementByte => memory[mem_ptr] -= 1,
Operations::IncrementPtr => mem_ptr += 1,
Operations::DecrementPtr => mem_ptr -= 1,
Operations::Read => log_ptr(&[memory[mem_ptr] as u8]),
Operations::StartLoop => bracket_idx.push(code_ptr),
Operations::EndLoop => {
if memory[mem_ptr] != 0 {
code_ptr = *bracket_idx.last().unwrap()
}
else {
bracket_idx.pop();
}
},
_ => println!("ERROR")
};
code_ptr += 1;
}
println!("{:?}", memory);
}
第一次进入循环时,当前值为1(因为循环前有一个+
)。在循环内,然后从该值中减去 5(因为有 5 个 -
)。因此,如果从 0 中减去导致溢出错误,则此程序将无法运行。
因此,要使该程序正常运行,您需要使用 wrapping_*
系列方法来环绕而不是在溢出时出现恐慌。
大多数整数运算以不同的形式存在:
carrying_*
(例如u8::carrying_u8
);overflowing_*
(例如u8::overflowing_u8
);saturating_*
(例如u8::saturating_u8
);unchecked_*
(例如u8::unchecked_u8
);wrapping_*
(例如u8::wrapping_u8
)。
这些中的每一个都允许对发生不足或溢出时发生的情况进行不同级别的控制。在这种情况下,您需要决定您希望您的应用程序做什么,并选择相关的方法。
还有包装器类型,例如 std::num::Wrapping
and std::num::Saturating
如果您始终希望所有操作都具有给定的行为,它会提供更简洁的语法。