1pub use self::parser::{parse, Token, Tokenizer};
5use b2c2_common::*;
6use std::fmt;
7
8mod parser;
9pub mod utils;
10
11#[cfg(test)]
12mod test;
13
14#[derive(PartialEq, Eq, Clone, Debug)]
15pub enum Statement {
16 Comment {
17 indent: usize,
18 text: String,
19 },
20 Code {
21 label: Option<Label>,
22 command: Command,
23 comment: Option<String>,
24 },
25}
26
27impl Statement {
28 pub fn labeled(label: &str, command: Command) -> Self {
29 Self::Code {
30 label: Some(label.into()),
31 command,
32 comment: None,
33 }
34 }
35
36 pub fn code(command: Command) -> Self {
37 Self::Code {
38 label: None,
39 command,
40 comment: None,
41 }
42 }
43
44 #[cfg(test)]
45 pub fn labeled_with_comment(label: &str, command: Command, comment: &str) -> Self {
46 Self::Code {
47 label: Some(label.into()),
48 command,
49 comment: Some(comment.into()),
50 }
51 }
52
53 #[cfg(test)]
54 pub fn code_with_comment(command: Command, comment: &str) -> Self {
55 Self::Code {
56 label: None,
57 command,
58 comment: Some(comment.into()),
59 }
60 }
61
62 #[cfg(test)]
63 pub fn comment(comment: &str) -> Self {
64 Self::Comment {
65 indent: 0,
66 text: comment.into(),
67 }
68 }
69
70 pub fn comment_with_indent(indent: usize, comment: &str) -> Self {
71 Self::Comment {
72 indent,
73 text: comment.into(),
74 }
75 }
76
77 pub fn is_comment(&self) -> bool {
78 matches!(self, Self::Comment { .. })
79 }
80
81 pub fn is_code(&self) -> bool {
82 !self.is_comment()
83 }
84}
85
86#[derive(PartialEq, Eq, Hash, Clone, Debug)]
87pub struct Label(String);
88
89impl From<String> for Label {
90 fn from(s: String) -> Self {
91 Label(s)
92 }
93}
94
95impl From<&str> for Label {
96 fn from(s: &str) -> Self {
97 Label(s.into())
98 }
99}
100
101impl From<&String> for Label {
102 fn from(s: &String) -> Self {
103 Label(s.clone())
104 }
105}
106
107impl Label {
108 pub fn as_str(&self) -> &str {
109 let Label(label) = self;
110 label
111 }
112
113 pub fn as_string(&self) -> &String {
114 let Label(label) = self;
115 label
116 }
117
118 pub fn is_valid(&self) -> bool {
119 let Label(label) = self;
120 let mut chars = label.chars();
121 if chars.next().filter(|ch| ch.is_ascii_uppercase()).is_none() {
122 return false;
123 }
124 if !chars.all(|ch| ch.is_ascii_uppercase() || ch.is_ascii_digit()) {
125 return false;
126 }
127 if label.chars().count() > 8 {
128 return false;
129 }
130 !matches!(
131 label.as_str(),
132 "GR0" | "GR1" | "GR2" | "GR3" | "GR4" | "GR5" | "GR6" | "GR7"
133 )
134 }
135}
136
137#[derive(PartialEq, Eq, Hash, Clone, Debug)]
138pub enum Adr {
139 Dec(i16), Hex(u16), Label(Label), LiteralDec(i16), LiteralHex(u16), LiteralStr(String), }
146
147impl From<Label> for Adr {
148 fn from(label: Label) -> Self {
149 Self::Label(label)
150 }
151}
152
153impl From<&Label> for Adr {
154 fn from(label: &Label) -> Self {
155 Self::Label(label.clone())
156 }
157}
158
159impl Adr {
160 pub fn label(label: &str) -> Self {
161 Self::Label(label.into())
162 }
163}
164
165#[derive(PartialEq, Eq, Clone, Debug)]
166pub enum Constant {
167 Dec(i16), Hex(u16), Str(String), Label(Label), }
172
173impl From<i16> for Constant {
174 fn from(v: i16) -> Self {
175 Self::Dec(v)
176 }
177}
178
179impl From<u16> for Constant {
180 fn from(v: u16) -> Self {
181 Self::Hex(v)
182 }
183}
184
185impl From<String> for Constant {
186 fn from(v: String) -> Self {
187 Self::Str(v)
188 }
189}
190
191impl From<&str> for Constant {
192 fn from(v: &str) -> Self {
193 Self::Str(v.into())
194 }
195}
196
197impl From<Label> for Constant {
198 fn from(v: Label) -> Self {
199 Self::Label(v)
200 }
201}
202
203impl From<&Label> for Constant {
204 fn from(v: &Label) -> Self {
205 Self::Label(v.clone())
206 }
207}
208
209#[derive(PartialEq, Eq, Clone, Copy, Debug)]
210pub enum Register {
211 Gr0 = 0,
212 Gr1 = 1,
213 Gr2 = 2,
214 Gr3 = 3,
215 Gr4 = 4,
216 Gr5 = 5,
217 Gr6 = 6,
218 Gr7 = 7,
219}
220
221#[derive(PartialEq, Eq, Clone, Copy, Debug)]
222pub enum IndexRegister {
223 Gr1 = 1,
224 Gr2 = 2,
225 Gr3 = 3,
226 Gr4 = 4,
227 Gr5 = 5,
228 Gr6 = 6,
229 Gr7 = 7,
230}
231
232impl From<IndexRegister> for Register {
233 fn from(r: IndexRegister) -> Self {
234 use IndexRegister::*;
235 match r {
236 Gr1 => Self::Gr1,
237 Gr2 => Self::Gr2,
238 Gr3 => Self::Gr3,
239 Gr4 => Self::Gr4,
240 Gr5 => Self::Gr5,
241 Gr6 => Self::Gr6,
242 Gr7 => Self::Gr7,
243 }
244 }
245}
246
247impl std::convert::TryFrom<Register> for IndexRegister {
248 type Error = ();
249 fn try_from(r: Register) -> Result<Self, Self::Error> {
250 use Register::*;
251 let ir = match r {
252 Gr0 => return Err(()),
253 Gr1 => Self::Gr1,
254 Gr2 => Self::Gr2,
255 Gr3 => Self::Gr3,
256 Gr4 => Self::Gr4,
257 Gr5 => Self::Gr5,
258 Gr6 => Self::Gr6,
259 Gr7 => Self::Gr7,
260 };
261 Ok(ir)
262 }
263}
264
265impl std::convert::TryFrom<&str> for IndexRegister {
266 type Error = ();
267 fn try_from(s: &str) -> Result<Self, Self::Error> {
268 let s = s.to_ascii_uppercase();
269 let ir = match s.as_str() {
270 "GR1" => Self::Gr1,
271 "GR2" => Self::Gr2,
272 "GR3" => Self::Gr3,
273 "GR4" => Self::Gr4,
274 "GR5" => Self::Gr5,
275 "GR6" => Self::Gr6,
276 "GR7" => Self::Gr7,
277 _ => return Err(()),
278 };
279 Ok(ir)
280 }
281}
282impl std::convert::TryFrom<&str> for Register {
283 type Error = ();
284 fn try_from(s: &str) -> Result<Self, Self::Error> {
285 let s = s.to_ascii_uppercase();
286 let ir = match s.as_str() {
287 "GR0" => Self::Gr0,
288 "GR1" => Self::Gr1,
289 "GR2" => Self::Gr2,
290 "GR3" => Self::Gr3,
291 "GR4" => Self::Gr4,
292 "GR5" => Self::Gr5,
293 "GR6" => Self::Gr6,
294 "GR7" => Self::Gr7,
295 _ => return Err(()),
296 };
297 Ok(ir)
298 }
299}
300
301#[derive(PartialEq, Eq, Clone, Copy, Debug)]
302pub enum R {
303 Ld,
304 Adda,
305 Addl,
306 Suba,
307 Subl,
308 And,
309 Or,
310 Xor,
311 Cpa,
312 Cpl,
313}
314
315#[derive(PartialEq, Eq, Clone, Copy, Debug)]
316pub enum A {
317 Ld,
318 St,
319 Lad,
320 Adda,
321 Addl,
322 Suba,
323 Subl,
324 And,
325 Or,
326 Xor,
327 Cpa,
328 Cpl,
329 Sla,
330 Sra,
331 Sll,
332 Srl,
333}
334
335#[derive(PartialEq, Eq, Clone, Copy, Debug)]
336pub enum P {
337 Jpl,
338 Jmi,
339 Jnz,
340 Jze,
341 Jov,
342 Jump,
343 Push,
344 Call,
345 Svc,
346}
347
348#[derive(PartialEq, Eq, Clone, Debug)]
349pub enum Command {
350 Start {
351 entry_point: Option<Label>,
352 },
353 End,
354 Ds {
355 size: u16,
356 },
357 Dc {
358 constants: Vec<Constant>,
359 },
360 In {
361 pos: Label,
362 len: Label,
363 },
364 Out {
365 pos: Label,
366 len: Label,
367 },
368 Rpush,
369 Rpop,
370
371 R {
372 code: R,
373 r1: Register,
374 r2: Register,
375 },
376 A {
377 code: A,
378 r: Register,
379 adr: Adr,
380 x: Option<IndexRegister>,
381 },
382 P {
383 code: P,
384 adr: Adr,
385 x: Option<IndexRegister>,
386 },
387 Pop {
388 r: Register,
389 },
390 Ret,
391 Nop,
392 DebugBasicStep {
393 id: usize,
394 },
395}
396
397#[cfg(test)]
398#[derive(Clone, Debug)]
399pub struct Program {
400 statements: Vec<Statement>,
401}
402
403#[cfg(test)]
404#[derive(Clone, Debug)]
405pub struct Builder {
406 label: Option<Label>,
407 program: Program,
408}
409
410#[cfg(test)]
411impl Builder {
412 pub fn new(name: &str) -> Self {
413 let statements = vec![Statement::Code {
414 label: Some(Label(name.into())),
415 command: Command::Start { entry_point: None },
416 comment: None,
417 }];
418 Self {
419 label: None,
420 program: Program { statements },
421 }
422 }
423
424 pub fn label(mut self, label: &str) -> Self {
425 self.label = Some(Label(label.into()));
426 self
427 }
428
429 pub fn code(mut self, command: Command) -> Self {
430 let label = self.label.take();
431 self.program.statements.push(Statement::Code {
432 label,
433 command,
434 comment: None,
435 });
436 self
437 }
438
439 pub fn code_with_comment(mut self, command: Command, comment: &str) -> Self {
440 let label = self.label.take();
441 self.program.statements.push(Statement::Code {
442 label,
443 command,
444 comment: Some(comment.into()),
445 });
446 self
447 }
448
449 fn comment(mut self, comment: &str) -> Self {
450 self.program.statements.push(Statement::Comment {
451 indent: 0,
452 text: comment.into(),
453 });
454 self
455 }
456
457 fn end(mut self) -> Program {
458 let label = self.label.take();
459 self.program.statements.push(Statement::Code {
460 label,
461 command: Command::End,
462 comment: None,
463 });
464 self.program
465 }
466}
467
468#[cfg(test)]
469impl fmt::Display for Program {
470 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
471 for s in self.statements.iter() {
472 writeln!(f, "{}", s.to_string())?;
473 }
474 Ok(())
475 }
476}
477
478impl fmt::Display for Label {
479 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
480 let Label(label) = self;
481 label.fmt(f)
482 }
483}
484
485impl fmt::Display for Adr {
486 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
487 match self {
488 Adr::Dec(v) => format!("{}", *v).fmt(f),
489 Adr::Hex(v) => format!("#{:04X}", *v).fmt(f),
490 Adr::Label(v) => format!("{}", v).fmt(f),
491 Adr::LiteralDec(v) => format!("={}", *v).fmt(f),
492 Adr::LiteralHex(v) => format!("=#{:04X}", *v).fmt(f),
493 Adr::LiteralStr(v) => format!("='{}'", v.replace('\'', "''")).fmt(f),
494 }
495 }
496}
497
498impl fmt::Display for Constant {
499 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
500 match self {
501 Constant::Dec(v) => format!("{}", *v).fmt(f),
502 Constant::Hex(v) => format!("#{:04X}", *v).fmt(f),
503 Constant::Str(v) => format!("'{}'", v.replace('\'', "''")).fmt(f),
504 Constant::Label(v) => format!("{}", v).fmt(f),
505 }
506 }
507}
508
509impl fmt::Display for Register {
510 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
511 format!("GR{}", *self as isize).fmt(f)
512 }
513}
514
515impl fmt::Display for IndexRegister {
516 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
517 format!("GR{}", *self as isize).fmt(f)
518 }
519}
520
521impl fmt::Display for R {
522 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
523 use R::*;
524 let s = match self {
525 Ld => "LD",
526 Adda => "ADDA",
527 Addl => "ADDL",
528 Suba => "SUBA",
529 Subl => "SUBL",
530 And => "AND",
531 Or => "OR",
532 Xor => "XOR",
533 Cpa => "CPA",
534 Cpl => "CPL",
535 };
536 s.fmt(f)
537 }
538}
539
540impl fmt::Display for A {
541 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
542 use A::*;
543 let s = match self {
544 Ld => "LD",
545 St => "ST",
546 Lad => "LAD",
547 Adda => "ADDA",
548 Addl => "ADDL",
549 Suba => "SUBA",
550 Subl => "SUBL",
551 And => "AND",
552 Or => "OR",
553 Xor => "XOR",
554 Cpa => "CPA",
555 Cpl => "CPL",
556 Sla => "SLA",
557 Sra => "SRA",
558 Sll => "SLL",
559 Srl => "SRL",
560 };
561 s.fmt(f)
562 }
563}
564
565impl fmt::Display for P {
566 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
567 use P::*;
568 let s = match self {
569 Jpl => "JPL",
570 Jmi => "JMI",
571 Jnz => "JNZ",
572 Jze => "JZE",
573 Jov => "JOV",
574 Jump => "JUMP",
575 Push => "PUSH",
576 Call => "CALL",
577 Svc => "SVC",
578 };
579 s.fmt(f)
580 }
581}
582
583impl fmt::Display for Command {
584 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
585 use Command::*;
586 let s = match self {
587 Start {
588 entry_point: Some(entry),
589 } => format!("{:<9} {}", "START", entry),
590 Start { entry_point: None } => return "START".fmt(f),
591 End => return "END".fmt(f),
592 Ds { size } => format!("{:<9} {}", "DS", *size),
593 Dc { constants } => {
594 let mut s = format!("{:<9} ", "DC");
595 for (i, c) in constants.iter().enumerate() {
596 if i > 0 {
597 s.push(',');
598 }
599 s.push_str(&c.to_string());
600 }
601 s
602 }
603 In { pos, len } => format!("{:<9} {},{}", "IN", pos, len),
604 Out { pos, len } => format!("{:<9} {},{}", "OUT", pos, len),
605 Rpush => return "RPUSH".fmt(f),
606 Rpop => return "RPOP".fmt(f),
607
608 R { code, r1, r2 } => format!("{:<9} {},{}", code.to_string(), r1, r2),
609 A {
610 code,
611 r,
612 adr,
613 x: Some(x),
614 } => format!("{:<9} {},{},{}", code.to_string(), r, adr, x),
615 A {
616 code,
617 r,
618 adr,
619 x: None,
620 } => format!("{:<9} {},{}", code.to_string(), r, adr),
621 P {
622 code,
623 adr,
624 x: Some(x),
625 } => format!("{:<9} {},{}", code.to_string(), adr, x),
626 P { code, adr, x: None } => format!("{:<9} {}", code.to_string(), adr),
627 Pop { r } => format!("{:<9} {}", "POP", r),
628 Ret => return "RET".fmt(f),
629 Nop => return "NOP".fmt(f),
630 DebugBasicStep { id } => format!("NOP ; DEBUGBASICSTEP {}", id),
631 };
632 s.fmt(f)
633 }
634}
635
636impl fmt::Display for Statement {
637 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
638 let s = match self {
639 Self::Comment { indent, text } => format!("{0:1$}; {2}", "", indent, text),
640 Self::Code {
641 label,
642 command,
643 comment: Some(text),
644 } => {
645 let command = command.to_string();
646 let count = command.chars().count();
647 let width = (count + 5 - count % 5).max(25);
648 if let Some(label) = label {
649 format!(
650 "{0:<9} {1:<2$}; {3}",
651 label.to_string(),
652 command,
653 width,
654 text
655 )
656 } else {
657 format!("{0:<9} {1:<2$}; {3}", "", command, width, text)
658 }
659 }
660 Self::Code {
661 label,
662 command,
663 comment: None,
664 } => {
665 if let Some(label) = label {
666 format!("{:<9} {}", label.to_string(), command)
667 } else {
668 format!("{:<9} {}", "", command)
669 }
670 }
671 };
672 s.fmt(f)
673 }
674}