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