%start SectionDefs %% SectionDefs -> Vec: SectionDefs SectionDef { $1.push($2); $1 } | { Vec::new() } ; SectionDef -> SectionDef: 'DIR_META' MetaBlock { SectionDef::Meta(MetaSection { lines: $2 }) } | 'DIR_SECTION' Name SectionOrg DataBlock { SectionDef::Data(DataSection { name: $2, org: $3, lines: $4, }) } ; MetaBlock -> Vec: 'LBRACE' MetaLines 'RBRACE' { $2 }; MetaLines -> Vec: MetaLines MetaLine { $1.push($2); $1 } | { Vec::new() } ; MetaLine -> MetaLine: Name 'COLON' Value { MetaLine { name: $1, value: $3 } }; SectionOrg -> SectionOrg: Int { SectionOrg::Start($1) } | Int 'DOTDOT' Int { SectionOrg::StartEnd($1, $3) } ; DataBlock -> Vec: 'LBRACE' DataLines 'RBRACE' { $2 }; DataLines -> Vec: DataLines DataLine { $1.push($2); $1 } | { Vec::new() } ; DataLine -> DataLine: ValueDef { DataLine::ValueDef($1) } | Inst { DataLine::Inst($1) } | 'DIR_EXPORT' Name { DataLine::Export($2) } | Name 'COLON' { DataLine::Label($1) } ; ValueDef -> ValueDef: 'INT_DEF' Int { ValueDef::Int($2) } | 'STR_DEF' String { ValueDef::String($2) } | 'ZSTR_DEF' String { ValueDef::ZString($2) } ; Value -> Value: Int { Value::Int($1) } | Reg { Value::Reg($1) } | Name { Value::Name($1) } | 'BUCKBUCK' { Value::Here } | 'LPAREN' Value 'RPAREN' { Value::Addr(Box::new($2), IntSize::U64) } | 'LPAREN' Value 'RPAREN' 'U8' { Value::Addr(Box::new($2), IntSize::U8) } | 'LPAREN' Value 'RPAREN' 'U16' { Value::Addr(Box::new($2), IntSize::U16) } | 'LPAREN' Value 'RPAREN' 'U32' { Value::Addr(Box::new($2), IntSize::U32) } | 'LPAREN' Value 'RPAREN' 'U64' { Value::Addr(Box::new($2), IntSize::U64) } ; Inst -> Inst: 'ADD' Value 'COMMA' Value { Inst::Add($2, $4) } | 'SUB' Value 'COMMA' Value { Inst::Sub($2, $4) } | 'MUL' Value 'COMMA' Value { Inst::Mul($2, $4) } | 'DIV' Value 'COMMA' Value { Inst::Div($2, $4) } | 'MOD' Value 'COMMA' Value { Inst::Mod($2, $4) } | 'AND' Value 'COMMA' Value { Inst::And($2, $4) } | 'OR' Value 'COMMA' Value { Inst::Or($2, $4) } | 'XOR' Value 'COMMA' Value { Inst::Xor($2, $4) } | 'SHL' Value 'COMMA' Value { Inst::Shl($2, $4) } | 'SHR' Value 'COMMA' Value { Inst::Shr($2, $4) } | 'INEG' Value 'COMMA' Value { Inst::INeg($2, $4) } | 'INV' Value 'COMMA' Value { Inst::Inv($2, $4) } | 'NOT' Value 'COMMA' Value { Inst::Not($2, $4) } | 'CMPEQ' Value 'COMMA' Value { Inst::CmpEq($2, $4) } | 'CMPLT' Value 'COMMA' Value { Inst::CmpLt($2, $4) } | 'JMP' Value { Inst::Jmp($2) } | 'JZ' Value { Inst::Jz($2) } | 'JNZ' Value { Inst::Jnz($2) } | 'MOV' Value 'COMMA' Value { Inst::Mov($2, $4) } | 'HALT' { Inst::Halt } | 'NOP' { Inst::Nop } | 'DUMP' { Inst::Dump } ; Name -> String: 'NAME' { let v = $1.expect("could not parse name"); $lexer.span_str(v.span()).to_string() } ; Int -> u64: 'DEC_INT' { let span = $1.expect("could not parse dec_int").span(); let s = &$lexer.span_str(span)[1..]; s.parse().unwrap() } | 'HEX_INT' { let span = $1.expect("could not parse hex_int").span(); let s = &$lexer.span_str(span)[3..]; u64::from_str_radix(s, 16).unwrap() } | 'BIN_INT' { let span = $1.expect("could not parse bin_int").span(); let s = &$lexer.span_str(span)[3..]; u64::from_str_radix(s, 2).unwrap() } ; Reg -> Reg: 'REG_IP' { IP } | 'REG_SP' { SP } | 'REG_FP' { FP } | 'REG_FLAGS' { FLAGS } | 'REG_NULL' { NULL } | 'REG_STATUS' { STATUS } | 'REG_GENERAL' { let v = $1.expect("could not parse reg"); parse_reg($lexer.span_str(v.span())).unwrap() } ; String -> String: 'STRING' { let v = $1.expect("could not parse string"); parse_string($lexer.span_str(v.span())) } ; %% use crate::vm::{ obj::syn::ast::*, reg::*, }; fn parse_string(input: &str) -> String { let mut s = String::new(); let input = &input[1..input.bytes().len() - 2]; let mut chars = input.chars(); while let Some(c) = chars.next() { if c == '\\' { let next = chars.next().unwrap(); let c = match next { '\\' => '\\', 'n' => '\n', 't' => '\t', '"' => '"', '\'' => '\'', '0' => '\0', _ => unreachable!(), }; s.push(c); } else { s.push(c); } } s } fn parse_reg(input: &str) -> Option { use regex::Regex; use lazy_static::lazy_static; lazy_static! { static ref REG_RE: Regex = Regex::new(r"^%r([0-9]{1,2})$").unwrap(); } let captures = REG_RE.captures(input)?; let reg_no: Reg = captures.get(1)? .as_str() .parse() .unwrap(); let reg = R00 + reg_no; if reg > R31 { None } else { Some(reg) } } #[cfg(test)] mod test { use crate::vm::reg::*; use super::parse_reg; #[test] fn test_parse_reg() { assert_eq!(parse_reg("%r00"), Some(R00)); assert_eq!(parse_reg("%r0"), Some(R00)); assert_eq!(parse_reg("%r1"), Some(R01)); assert_eq!(parse_reg("%r01"), Some(R01)); assert_eq!(parse_reg("%r31"), Some(R31)); assert_eq!(parse_reg("%r32"), None); assert_eq!(parse_reg("%r0000"), None); assert_eq!(parse_reg("%r9"), Some(R09)); assert_eq!(parse_reg("%r"), None); assert_eq!(parse_reg("%r12"), Some(R12)); } }