From 891f0b3d601c881716df8b1b3aadb0e27fc4d488 Mon Sep 17 00:00:00 2001 From: "freidlan@informatik.hu-berlin.de" <freidlan@informatik.hu-berlin.de> Date: Wed, 15 Jun 2022 22:14:31 +0200 Subject: [PATCH] =?UTF-8?q?L=C3=B6sung?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lexer.rs | 2 +- src/lib.rs | 4 +- src/parser.rs | 272 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 275 insertions(+), 3 deletions(-) create mode 100644 src/parser.rs diff --git a/src/lexer.rs b/src/lexer.rs index a955a4d..d71c6d9 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 82c0db8..1435b81 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 0000000..30fac85 --- /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 -- GitLab