boy-debug: Add extended identifier ("string") syntax + string expressions. Add load-file statements
This commit is contained in:
parent
054f9f49cb
commit
358dfb832a
@ -255,15 +255,21 @@ pub mod cli {
|
||||
}
|
||||
.emit(Token::Op(Range))
|
||||
}
|
||||
|
||||
fn string(&mut self) -> Option<Token> {
|
||||
let mut value = String::new();
|
||||
while let Some(c) = self.text.next_if(|&c| c != '"') {
|
||||
value.push(c)
|
||||
}
|
||||
self.take().emit(Token::Ident(value))
|
||||
}
|
||||
}
|
||||
impl<I: Iterator<Item = char>> Iterator for Lexer<I> {
|
||||
type Item = Token;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self.sync().peek()? {
|
||||
// '{' => self.take().emit(Op(CurlyOpen)),
|
||||
'[' => self.take().emit(Op(BrackOpen)),
|
||||
'(' => self.take().emit(Op(ParenOpen)),
|
||||
// '}' => self.take().emit(Op(CurlyClose)),
|
||||
']' => self.take().emit(Op(BrackClose)),
|
||||
')' => self.take().emit(Op(ParenClose)),
|
||||
|
||||
@ -280,6 +286,7 @@ pub mod cli {
|
||||
'>' => self.take().chain('>', Op(Shr)),
|
||||
'<' => self.take().chain('<', Op(Shl)),
|
||||
'.' => self.take().range(), // special handling allows for one or two dots
|
||||
'"' => self.take().string(), // string-packed identifiers
|
||||
|
||||
'?' => self.take().emit(Token::Ident("regs".into())),
|
||||
'$' | '#' => self.take().digits::<16>(),
|
||||
@ -358,7 +365,8 @@ pub mod cli {
|
||||
Expr::parse(lexer, 0)?,
|
||||
Expr::parse(lexer.then(Token::Op(Op::Comma))?, 0)?,
|
||||
],
|
||||
Verb::Get
|
||||
Verb::Load
|
||||
| Verb::Get
|
||||
| Verb::Run
|
||||
| Verb::Break
|
||||
| Verb::Unbreak
|
||||
@ -392,6 +400,7 @@ pub mod cli {
|
||||
"ub" | "unbreak" => Verb::Unbreak,
|
||||
"di" | "dis" => Verb::Disasm,
|
||||
"eval" => Verb::Eval,
|
||||
"load" => Verb::Load,
|
||||
"regs" => Verb::DumpRegs,
|
||||
"cart" => Verb::DumpCart,
|
||||
"trace" => Verb::Trace,
|
||||
@ -408,6 +417,7 @@ pub mod cli {
|
||||
Token::Reg(r) => Expr::Reg(r),
|
||||
Token::Num(n) => Expr::Int(n as _),
|
||||
Token::Bool(b) => Expr::Bool(b),
|
||||
Token::Ident(s) => Expr::String(s),
|
||||
Token::Op(Op::ParenOpen) => {
|
||||
let head = Expr::parse(p, 0)?;
|
||||
if p.then(Token::Op(Op::ParenClose)).is_none() {
|
||||
@ -581,6 +591,7 @@ pub mod ast {
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum Verb {
|
||||
Load,
|
||||
Set,
|
||||
Get,
|
||||
Run,
|
||||
@ -598,6 +609,7 @@ pub mod ast {
|
||||
impl Display for Verb {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Verb::Load => "load",
|
||||
Verb::Set => "set",
|
||||
Verb::Get => "get",
|
||||
Verb::Run => "run",
|
||||
@ -620,6 +632,7 @@ pub mod ast {
|
||||
Int(isize),
|
||||
Bool(bool),
|
||||
Reg(Reg),
|
||||
String(String),
|
||||
Prefix(Op, Box<Expr>),
|
||||
Binary(Op, Box<Expr>, Box<Expr>),
|
||||
Postfix(Op, Box<Expr>),
|
||||
@ -632,7 +645,7 @@ pub mod ast {
|
||||
/// Traverses the expression depth-first, calling function f() on every subexpression
|
||||
pub fn visit(&mut self, f: &impl Fn(&mut Expr)) {
|
||||
match self {
|
||||
Expr::Int(_) | Expr::Bool(_) | Expr::Reg(_) => {}
|
||||
Expr::Int(_) | Expr::Bool(_) | Expr::Reg(_) | Expr::String(_)=> {}
|
||||
Expr::Array(v) => v.iter_mut().for_each(|e| e.visit(f)),
|
||||
Expr::Prefix(_, e) | Expr::Postfix(_, e) => e.visit(f),
|
||||
Expr::Binary(_, a, b) | Expr::Range(a, b) | Expr::Index(a, b) => {
|
||||
@ -682,7 +695,7 @@ pub mod ast {
|
||||
/// Attempts to solve a top-level expression using basic arithmetic rules
|
||||
pub fn eval_one(&mut self) -> Option<Expr> {
|
||||
match self {
|
||||
Expr::Int(_) | Expr::Bool(_) | Expr::Reg(_) => None,
|
||||
Expr::Int(_) | Expr::Bool(_) | Expr::Reg(_) | Expr::String(_) => None,
|
||||
Expr::Array(_) | Expr::Range(_, _) => None,
|
||||
Expr::Prefix(op, e) => e.eval_prefix(*op),
|
||||
Expr::Binary(op, lhs, rhs) => lhs.eval_binary(*op, rhs),
|
||||
@ -743,6 +756,7 @@ pub mod ast {
|
||||
Expr::Int(i) => write!(f, "{i:02x}"),
|
||||
Expr::Bool(b) => b.fmt(f),
|
||||
Expr::Reg(r) => r.fmt(f),
|
||||
Expr::String(s) => write!(f, "\"{s}\""),
|
||||
Expr::Prefix(op, e) => write!(f, "{op}{e}"),
|
||||
Expr::Binary(op, a, b) => write!(f, "{a} {op} {b}"),
|
||||
Expr::Postfix(op, e) => write!(f, "{e}{op}"),
|
||||
@ -786,6 +800,7 @@ pub mod ast {
|
||||
Expr::Int(_)
|
||||
| Expr::Bool(_)
|
||||
| Expr::Reg(_)
|
||||
| Expr::String(_)
|
||||
| Expr::Prefix(_, _)
|
||||
| Expr::Binary(_, _, _)
|
||||
| Expr::Postfix(_, _)
|
||||
@ -893,6 +908,12 @@ pub mod gameboy {
|
||||
// Intrepret basic statements
|
||||
let Stmt { verb, dst, src } = stmt.solve(&Expr::eval_one);
|
||||
match (verb, dst, src) {
|
||||
(Verb::Load, Expr::String(file), ..) => {
|
||||
if let Err(e) = self.bus.read_file(file) {
|
||||
eprintln!("{e}");
|
||||
return Response::Failure
|
||||
}
|
||||
}
|
||||
(Verb::Set, Expr::Int(addr), Expr::Int(data)) => {
|
||||
self.bus.write(*addr as _, *data as _);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user