use crate::*; pub struct SyntacticParser { tokeniser: Tokeniser, tokens: Vec, /// The name of the macro being parsed. macro_name: Option, /// The name of the most recent label. label_name: String, } impl SyntacticParser { pub fn new>(source_code: &str, path: Option

) -> Self { let mut tokeniser = Tokeniser::new(source_code, path); tokeniser.add_delimiters(&['@','%',';',':','{','}','(','[','#','~']); Self { tokeniser, tokens: Vec::new(), macro_name: None, label_name: String::new(), } } pub fn parse(mut self) -> Vec { use SyntacticTokenVariant as SynVar; use SyntacticParseError as SynErr; let t = &mut self.tokeniser; loop { t.eat_whitespace(); t.mark_start(); let Some(c) = t.eat_char() else { break }; let variant = match c { ':' => SynVar::Separator, '{' => SynVar::BlockOpen, '}' => SynVar::BlockClose, '@' => match &self.macro_name { Some(_) => { t.eat_token(); SynVar::Error(SynErr::LabelInMacroDefinition) } None => { self.label_name = t.eat_token(); SynVar::LabelDefinition(self.label_name.clone()) } } '&' => match &self.macro_name { Some(macro_name) => { let label_name = format!("{macro_name}:{}", t.eat_token()); SynVar::LabelDefinition(label_name) } None => { let label_name = &self.label_name; let sublabel_name = format!("{label_name}/{}", t.eat_token()); SynVar::LabelDefinition(sublabel_name) } } '%' => { let macro_name = t.eat_token(); self.macro_name = Some(macro_name.clone()); SynVar::MacroDefinition(macro_name) } ';' => { self.macro_name = None; SynVar::MacroDefinitionTerminator } '[' => { t.mark_child(); match t.eat_to_delimiter(']') { Some(_) => { let child = t.subtokenise(); t.mark_end(); let expr = parse_constant_expression(child, t.get_source()); SynVar::Expression(expr) } None => SynVar::Error(SynErr::UnterminatedExpression), } } '(' => match t.eat_to_delimiter(')') { Some(string) => { // Check if the comment fills the entire line. if t.start.position.column == 0 && t.end_of_line() { if let Some(path) = string.strip_prefix(": ") { t.embedded_path = Some(PathBuf::from(path.trim())); t.embedded_first_line = t.start.position.line + 1; } } continue; }, None => SynVar::Error(SynErr::UnterminatedComment), } '|' => { let token = t.eat_token(); if let Some(hex_string) = token.strip_prefix("0x") { match usize::from_str_radix(hex_string, 16) { Ok(addr) => SynVar::PinnedAddress(addr), Err(_) => SynVar::Error(SynErr::InvalidHexadecimalLiteral(token)), } } else { match usize::from_str_radix(&token, 10) { Ok(addr) => SynVar::PinnedAddress(addr), Err(_) => SynVar::Error(SynErr::InvalidDecimalLiteral(token)), } } } '#' => { t.mark_child(); t.eat_token(); let pbl = parse_packed_binary_literal(t.subtokenise(), t.get_source()); SynVar::PackedBinaryLiteral(pbl) }, '~' => match &self.macro_name { Some(macro_name) => { let symbol_name = format!("{macro_name}:{}", t.eat_token()); SynVar::Symbol(symbol_name) } None => { let label_name = &self.label_name; let symbol_name = format!("{label_name}/{}", t.eat_token()); SynVar::Symbol(symbol_name) } } c => { let token = format!("{c}{}", t.eat_token()); if let Some(hex_string) = token.strip_prefix("0x") { match usize::from_str_radix(hex_string, 16) { Ok(value) => SynVar::IntegerLiteral(value as isize), Err(_) => SynVar::Error(SynErr::InvalidHexadecimalLiteral(token)), } } else { match usize::from_str_radix(&token, 10) { Ok(value) => SynVar::IntegerLiteral(value as isize), Err(_) => SynVar::Symbol(token), } } } }; t.mark_end(); let source = t.get_source(); self.tokens.push(SyntacticToken { source, variant }); } return self.tokens; } }