use crate::{C1Lexer, C1Token, ParseResult}; pub struct C1Parser<'a> { lx: C1Lexer<'a>, } impl C1Parser<'_> { pub fn parse(text: &'_ str) -> ParseResult { let mut parser: C1Parser = C1Parser { lx: C1Lexer::new(text) }; return Ok(parser.program()); } fn program(&mut self) { while self.lx.current_token().is_some() { let _ = self.functiondefinition(); } } fn functiondefinition(&mut self) -> ParseResult { self.statement_type()?; self.check_and_eat_token(Some(C1Token::Identifier))?; self.check_and_eat_token(Some(C1Token::LeftParenthesis))?; self.check_and_eat_token(Some(C1Token::RightParenthesis))?; self.check_and_eat_token(Some(C1Token::LeftBrace))?; self.statementlist()?; self.check_and_eat_token(Some(C1Token::RightBrace)) } fn statement_type(&mut self) -> ParseResult { return match self.lx.current_token() { Some(C1Token::KwBoolean) | Some(C1Token::KwFloat) | Some(C1Token::KwInt) | Some(C1Token::KwVoid) => { self.eat(); Result::Ok(()) }, _ => Result::Err(self.error_format()), }; } fn statementlist(&mut self) -> ParseResult { print!("statementlist->"); if self.lx.current_token() == Some(C1Token::RightBrace) { return Result::Ok(()); } self.block()?; self.statementlist() } fn block(&mut self) -> ParseResult { print!("block->"); if self.current_matches(C1Token::LeftBrace) { self.eat(); self.statementlist()?; return self.check_and_eat_token(Some(C1Token::RightBrace)); } self.statement() } fn statement(&mut self) -> ParseResult { print!("statement->"); return match self.lx.current_token() { Some(C1Token::KwIf) => self.ifstatement(), Some(C1Token::KwReturn) => { self.returnstatement()?; self.check_and_eat_token(Some(C1Token::Semicolon)) }, Some(C1Token::KwPrintf) => { self.printfstatement()?; self.check_and_eat_token(Some(C1Token::Semicolon)) }, Some(C1Token::Identifier) => { if self.next_matches(C1Token::LeftParenthesis) { self.functioncall()?; return self.check_and_eat_token(Some(C1Token::Semicolon)); } else if self.next_matches(C1Token::Assign) { self.statassignment()?; return self.check_and_eat_token(Some(C1Token::Semicolon)); } Result::Err(self.error_format()) }, _ => Result::Err(self.error_format()), }; } fn ifstatement(&mut self) -> ParseResult { self.check_and_eat_token(Some(C1Token::KwIf))?; self.check_and_eat_token(Some(C1Token::LeftParenthesis))?; self.assignment()?; self.check_and_eat_token(Some(C1Token::RightParenthesis))?; self.block() } fn returnstatement(&mut self) -> ParseResult { self.check_and_eat_token(Some(C1Token::KwReturn))?; self.returnstatement_alt() } fn returnstatement_alt(&mut self) -> ParseResult { if self.current_matches(C1Token::Semicolon) { return Result::Ok(()); }; self.assignment() } fn printfstatement(&mut self) -> ParseResult { self.check_and_eat_token(Some(C1Token::KwPrintf))?; self.check_and_eat_token(Some(C1Token::LeftParenthesis))?; self.assignment()?; self.check_and_eat_token(Some(C1Token::RightParenthesis)) } fn statassignment(&mut self) -> ParseResult { self.check_and_eat_token(Some(C1Token::Identifier))?; self.check_and_eat_token(Some(C1Token::Assign))?; self.assignment() } fn functioncall(&mut self) -> ParseResult { self.check_and_eat_token(Some(C1Token::Identifier))?; self.check_and_eat_token(Some(C1Token::LeftParenthesis))?; self.check_and_eat_token(Some(C1Token::RightParenthesis)) } fn assignment(&mut self) -> ParseResult { if self.current_matches(C1Token::Identifier) { if self.next_matches(C1Token::Assign) { return self.assignment(); } } self.expr() } fn expr(&mut self) -> ParseResult { print!("simplexpr->"); self.simpexpr()?; self.expr_2() } fn expr_2(&mut self) -> ParseResult { if self.current_matches(C1Token::Semicolon) || self.current_matches(C1Token::RightParenthesis) { return Result::Ok(()); } self.compare()?; self.simpexpr() } fn compare(&mut self) -> ParseResult { return match self.lx.current_token() { Some(C1Token::Equal) | Some(C1Token::NotEqual) | Some(C1Token::Less) | Some(C1Token::LessEqual) | Some(C1Token::GreaterEqual) | Some(C1Token::Greater) => { self.eat(); Result::Ok(()) }, _ => Result::Err(self.error_format()), } } fn simpexpr(&mut self) -> ParseResult { self.minus()?; self.term()?; self.simpexpr_2() } fn simpexpr_2(&mut self) -> ParseResult { match self.lx.current_token() { Some(C1Token::Plus) | Some(C1Token::Minus) | Some(C1Token::Or) => { self.lowop()?; self.term()?; self.simpexpr_2() }, _ => Result::Ok(()), } } fn minus(&mut self) -> ParseResult { if self.current_matches(C1Token::Minus) { self.eat(); }; return Result::Ok(()); } fn lowop(&mut self) -> ParseResult { return match self.lx.current_token() { Some(C1Token::Plus) | Some(C1Token::Minus) | Some(C1Token::Or) => { self.eat(); Result::Ok(()) }, _ => Result::Err(self.error_format()), }; } fn term(&mut self) -> ParseResult { self.factor()?; self.term_2() } fn term_2(&mut self) -> ParseResult { return match self.lx.current_token() { Some(C1Token::Asterisk) | Some(C1Token::Slash) | Some(C1Token::And) => { self.highop()?; self.factor()?; self.term_2() }, _ => Result::Ok(()), } } fn highop(&mut self) -> ParseResult { return match self.lx.current_token() { Some(C1Token::Asterisk) | Some(C1Token::Slash) | Some(C1Token::And) => { self.eat(); Result::Ok(()) }, _ => Result::Err(self.error_format()), }; } fn factor(&mut self) -> ParseResult { print!("factor->"); return match self.lx.current_token() { Some(C1Token::ConstFloat) | Some(C1Token::ConstInt) | Some(C1Token::ConstBoolean) => { self.eat(); Result::Ok(()) }, Some(C1Token::Identifier) => { if self.next_matches(C1Token::LeftParenthesis) { return self.functioncall(); } self.eat(); Result::Ok(()) }, Some(C1Token::LeftParenthesis) => { self.eat(); self.assignment()?; self.check_and_eat_token(Some(C1Token::RightParenthesis)) }, _ => Result::Err(self.error_format()), } } //konsumiert aktuelles Token fn eat(&mut self) { self.lx.eat(); } //Fehler wird zurückgegeben fn error_format(&self) -> String { return format!("Error on line: {}", self.lx.current_line_number().unwrap()); } //überprüft, ob das ihr übergebene Token gleich dem aktuellen fn check_and_eat_token(&mut self, token: Option<C1Token>) -> ParseResult { if self.lx.current_token() == token { self.eat(); return Result::Ok(()); } return Result::Err(self.error_format()); } //wie check_and_eat_token, gibt Vergleich zurück fn current_matches(&mut self, token: C1Token) -> bool { self.lx.current_token() == Some(token) } //wie check_and_eat_token für nächstes Token, gibt Vergleich zurück fn next_matches(&mut self, token: C1Token) -> bool { self.lx.peek_token() == Some(token) } }