b2c2_casl2/
lib.rs

1// b2c2-casl2 crate
2// author: Leonardone @ NEETSDKASU
3
4pub 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),           // -32678 ~ 32677
140    Hex(u16),           // #0000 ~ #FFFF
141    Label(Label),       // 'text'
142    LiteralDec(i16),    // =1234
143    LiteralHex(u16),    // =#12AB
144    LiteralStr(String), // ='text'
145}
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),     // =1234
168    Hex(u16),     // =#12AB
169    Str(String),  // ='text'
170    Label(Label), // 'text'
171}
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}