Most everything works, but there's one small bug with the execution involving jumps - still have to figure that one out. Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
200 lines
5.3 KiB
Plaintext
200 lines
5.3 KiB
Plaintext
%start SectionDefs
|
|
%%
|
|
|
|
SectionDefs -> Vec<SectionDef>:
|
|
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<MetaLine>: 'LBRACE' MetaLines 'RBRACE' { $2 };
|
|
|
|
MetaLines -> Vec<MetaLine>:
|
|
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<DataLine>: 'LBRACE' DataLines 'RBRACE' { $2 };
|
|
|
|
DataLines -> Vec<DataLine>:
|
|
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 }
|
|
;
|
|
|
|
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<Reg> {
|
|
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));
|
|
}
|
|
}
|