diff --git a/src/lexer.rs b/src/lexer.rs index a955a4d247f1834e8d0c383868ad8c2efe3f5b97..d71c6d9d3850bf5b9444e97f424a5e933932c391 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -131,7 +131,7 @@ pub enum C1Token { #[regex(r"[ \t\f]+", logos::skip)] Whitespace, - #[regex(r"[\n]")] + #[regex(r"(\r\n|\r|\n)")] Linebreak, // Logos requires one token variant to handle errors, diff --git a/src/lib.rs b/src/lib.rs index 82c0db8fd7e41520a9886ced779de3a11bd292c8..1435b814f2f26550bffb11f81fd1280d448080cc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ mod lexer; +mod parser; // Type definition for the Result that is being used by the parser. You may change it to anything // you want @@ -8,5 +9,4 @@ pub use lexer::C1Lexer; pub use lexer::C1Token; // You will need a re-export of your C1Parser definition. Here is an example: -// mod parser; -// pub use parser::C1Parser; +pub use parser::C1Parser; diff --git a/src/parser.rs b/src/parser.rs new file mode 100644 index 0000000000000000000000000000000000000000..30fac850778bf0e53bdc7349ef466312eb7cc47b --- /dev/null +++ b/src/parser.rs @@ -0,0 +1,272 @@ +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) + } +} \ No newline at end of file