Use lrpar for parsing, big 'ol syntax overhaul
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
204
src/vm/obj/syn/parser.y
Normal file
204
src/vm/obj/syn/parser.y
Normal file
@@ -0,0 +1,204 @@
|
||||
%start SectionDefs
|
||||
%%
|
||||
|
||||
SectionDefs -> Vec<SectionDef>:
|
||||
SectionDefs SectionDef { $1.push($2); $1 }
|
||||
| { Vec::new() }
|
||||
;
|
||||
|
||||
SectionDef -> SectionDef:
|
||||
'DIR_META' MetaBlock { SectionDef::Meta(MetaSection { values: $2 }) }
|
||||
| 'DIR_SECTION' Name MaybeSectionOrg 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 } };
|
||||
|
||||
MaybeSectionOrg -> Option<SectionOrg>:
|
||||
SectionOrg { Some($1) }
|
||||
| { None }
|
||||
;
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user