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

) -> Self { let mut tokeniser = Tokeniser::new(source_code, path); tokeniser.add_delimiters(&['@','&','%',';',':','{','}','(','[','#','~']); Self { tokeniser, label_name: String::new(), macro_name: None, } } } impl Iterator for SyntacticParser { type Item = Token; /// Sequentially parse tokens from the source code. fn next(&mut self) -> Option { let t = &mut self.tokeniser; t.drop_whitespace(); t.mark_start_position(); let variant = match t.eat_char()? { '@' => { self.label_name = t.eat_token(); TokenVariant::LabelDefinition(self.label_name.clone()) } '&' => { let token = t.eat_token(); TokenVariant::LabelDefinition(format!("{}/{token}", self.label_name)) } '%' => { let macro_name = t.eat_token(); self.macro_name = Some(macro_name.clone()); TokenVariant::MacroDefinition(macro_name) } ';' => { self.macro_name = None; TokenVariant::MacroDefinitionTerminator } '[' => match t.eat_to_delimiter(']') { Some(string) => { let constant = ConstantExpression::from_str(&string, t); TokenVariant::ConstantExpression(constant) } None => TokenVariant::Error(ParseError::UnterminatedConstantExpression), } '{' => TokenVariant::BlockOpen, '}' => TokenVariant::BlockClose, '(' => match t.eat_to_delimiter(')') { Some(string) => TokenVariant::Comment(string), None => TokenVariant::Error(ParseError::UnterminatedComment), } '#' => { let token = t.eat_token(); let pbl = PackedBinaryLiteral::from_str(&token, t); TokenVariant::PackedBinaryLiteral(pbl) }, '~' => { let token = t.eat_token(); TokenVariant::Symbol(format!("{}/{token}", self.label_name)) } ':' => TokenVariant::Separator, 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(hex) => TokenVariant::HexadecimalLiteral(hex), Err(_) => TokenVariant::Error(ParseError::InvalidHexadecimalLiteral(token)), } } else { match usize::from_str_radix(&token, 10) { Ok(value) => TokenVariant::DecimalLiteral(value), Err(_) => TokenVariant::Symbol(token), } } } }; // Parse source path comments. if let TokenVariant::Comment(comment) = &variant { // Check if the comment fills the entire line. if t.start_position.column == 0 && t.end_of_line() { if let Some(path) = comment.strip_prefix(": ") { t.embedded_path = Some(PathBuf::from(path.trim())); t.embedded_first_line = t.start_position.line + 1; } } } let source = t.mark_end_position(); Some( Token { source, variant } ) } }