From 14e06f870b8f3cced4f5d153eb4a08099830e5a7 Mon Sep 17 00:00:00 2001 From: Paul <der.paul.ammann@gmail.com> Date: Tue, 14 Jun 2022 14:42:18 +0200 Subject: [PATCH] Init --- src/C1_parser.rs | 289 +++++++++++++++++++++++++++++++++++++++++++++++ src/lexer.rs | 4 + src/lib.rs | 2 + tests/parser.rs | 3 + 4 files changed, 298 insertions(+) create mode 100644 src/C1_parser.rs diff --git a/src/C1_parser.rs b/src/C1_parser.rs new file mode 100644 index 0000000..127809a --- /dev/null +++ b/src/C1_parser.rs @@ -0,0 +1,289 @@ +use std::fs::File; +use crate::{C1Lexer, C1Token, lexer, ParseResult}; + +pub struct C1Parser<'a> { + lx: C1Lexer<'a>, +} + +impl<'a> C1Parser<'a> { + fn new(text: &str) -> C1Parser { + C1Parser { + lx: C1Lexer::new(text), + } + } + + pub fn parse(text: &str) -> ParseResult { + let mut instance = C1Parser::new(text); + + println!("Starting parsing"); + + instance.program().unwrap(); + + Ok(()) + } + + fn program(&mut self) -> ParseResult { + self.functiondefinition().unwrap(); + Ok(()) + } + + fn functiondefinition(&mut self) -> ParseResult { + if self.lx.current_token() == Some(C1Token::KwInt) || self.lx.current_token() == Some(C1Token::KwVoid) || self.lx.current_token() == Some(C1Token::KwBoolean) || self.lx.current_token() == Some(C1Token::KwFloat) { + self.lx.eat(); + + self.check_and_eat_token(C1Token::Identifier).unwrap(); + self.check_and_eat_token(C1Token::LeftParenthesis).unwrap(); + self.check_and_eat_token(C1Token::RightParenthesis).unwrap(); + self.check_and_eat_token(C1Token::LeftBrace).unwrap(); + self.statementlist().unwrap(); + self.check_and_eat_token(C1Token::RightBrace).unwrap(); + + return Ok(()); + } + return Err(format!("Expected token group 'type' but found {:?}", self.lx.current_token())); + } + + fn statementlist(&mut self) -> ParseResult { + print!("statementlist->"); + //self.block().unwrap(); //TODO: While loop + + /*if self.lx.current_token() == Some(C1Token::LeftBrace) && self.lx.peek_token() == Some(C1Token::RightBrace) { + self.lx.eat(); + self.lx.eat(); + println!("eat"); + return Ok(()); + } + + + if self.lx.current_token() == Some(C1Token::LeftBrace){ + self.check_and_eat_token(C1Token::LeftBrace).unwrap(); + + while !(self.lx.current_token() == Some(C1Token::RightBrace)) { + println!("r"); + + if self.lx.current_token() == Some(C1Token::LeftBrace){ + self.statementlist().unwrap(); + } + + self.statement().unwrap(); + } + println!("block finished!!!"); + + self.check_and_eat_token(C1Token::RightBrace).unwrap(); + }*/ + + while !(self.lx.current_token() == Some(C1Token::RightBrace)) { + self.block().unwrap(); + } + + Ok(()) + } + + fn block(&mut self) -> ParseResult { + print!("block->"); + if self.lx.current_token() == Some(C1Token::LeftBrace){ + self.check_and_eat_token(C1Token::LeftBrace).unwrap(); + self.statementlist().unwrap(); + self.check_and_eat_token(C1Token::RightBrace).unwrap(); + }else{ + self.statement().unwrap(); + } + Ok(()) + } + + fn statement(&mut self) -> ParseResult { + print!("statement->"); + match self.lx.current_token() { + Some(C1Token::KwIf) => { + self.ifstatement().unwrap(); + Ok(()) + }, + Some(C1Token::KwReturn) => { + self.returnstatement().unwrap(); + self.check_and_eat_token(C1Token::Semicolon).unwrap(); + Ok(()) + }, + Some(C1Token::KwPrintf) => { + self.printfstatement().unwrap(); + self.check_and_eat_token(C1Token::Semicolon).unwrap(); + Ok(()) + }, + Some(C1Token::Identifier) => { + if self.lx.peek_token() == Some(C1Token::Assign) { + self.statassignment().unwrap(); + self.check_and_eat_token(C1Token::Semicolon).unwrap(); + }else{ + self.functioncall().unwrap(); + self.check_and_eat_token(C1Token::Semicolon).unwrap(); + } + Ok(()) + }, + _ => Err(format!("Expected token group 'statement' but found {:?}", self.lx.current_token().unwrap())), + } + } + + fn functioncall(&mut self) -> ParseResult { + print!("functioncall->"); + self.check_and_eat_token(C1Token::Identifier).unwrap(); + self.check_and_eat_token(C1Token::LeftParenthesis).unwrap(); + self.check_and_eat_token(C1Token::RightParenthesis).unwrap(); + Ok(()) + } + + fn statassignment(&mut self) -> ParseResult { + print!("statassignment->"); + self.check_and_eat_token(C1Token::Identifier).unwrap(); + self.check_and_eat_token(C1Token::Assign).unwrap(); + self.assignment().unwrap(); + Ok(()) + } + + + fn returnstatement(&mut self) -> ParseResult { + print!("returnstatement->"); + self.check_and_eat_token(C1Token::KwReturn).unwrap(); + self.assignment(); //TODO: Maybe? + Ok(()) + } + + fn printfstatement(&mut self) -> ParseResult { + print!("printfstatement->"); + self.check_and_eat_token(C1Token::KwPrintf).unwrap(); + self.check_and_eat_token(C1Token::LeftParenthesis).unwrap(); + self.assignment().unwrap(); + self.check_and_eat_token(C1Token::RightParenthesis).unwrap(); + Ok(()) + } + + fn ifstatement(&mut self) -> ParseResult { + print!("ifstatement->"); + self.check_and_eat_token(C1Token::KwIf).unwrap(); + self.check_and_eat_token(C1Token::LeftParenthesis).unwrap(); + self.assignment().unwrap(); + //TODO: self.check_and_eat_token(C1Token::RightParenthesis).unwrap(); + self.block().unwrap(); + Ok(()) + } + + fn assignment(&mut self) -> ParseResult { + print!("assignment->"); + println!("test: {:?} {:?}", self.lx.current_text(), self.lx.peek_text()); + if self.lx.current_token() == Some(C1Token::Identifier) && self.lx.peek_token() == Some(C1Token::Assign) { + self.check_and_eat_token(C1Token::Identifier).unwrap(); + self.check_and_eat_token(C1Token::Assign).unwrap(); + self.assignment().unwrap(); + return Ok(()); + }else{ + println!("assignment: Not Identifier"); + self.expr().unwrap(); + return Ok(()); + } + } + + fn expr(&mut self) -> ParseResult { + print!("expr->"); + self.simpexpr().unwrap(); + + let tk = self.lx.current_token(); + if tk == Some(C1Token::Equal) || tk == Some(C1Token::NotEqual) || tk == Some(C1Token::Less) || tk == Some(C1Token::LessEqual) || tk == Some(C1Token::Greater) || tk == Some(C1Token::GreaterEqual) { + self.lx.eat(); + self.simpexpr().unwrap(); + }else{ + return Ok(()); + } + self.check_and_eat_token(C1Token::RightParenthesis).unwrap(); + Ok(()) + } + + fn simpexpr(&mut self) -> ParseResult { + print!("simpexpr->"); + if self.lx.current_token() == Some(C1Token::Minus){ + self.check_and_eat_token(C1Token::Minus).unwrap(); + } + self.term().unwrap(); + + while self.lx.current_token() == Some(C1Token::Plus) || self.lx.current_token() == Some(C1Token::Minus) || self.lx.current_token() == Some(C1Token::Or) { + self.lx.eat(); + self.term().unwrap(); + } + Ok(()) + } + + fn term(&mut self) -> ParseResult { + print!("term->"); + self.factor().unwrap(); + + while self.lx.current_token() == Some(C1Token::Asterisk) || self.lx.current_token() == Some(C1Token::Slash) || self.lx.current_token() == Some(C1Token::And) { + self.lx.eat(); + self.factor().unwrap(); + } + Ok(()) + } + + fn factor(&mut self) -> ParseResult { + print!("factor->"); + + + + match self.lx.current_token() { + Some(C1Token::ConstInt) => { + self.check_and_eat_token(C1Token::ConstInt).unwrap(); + Ok(()) + }, + Some(C1Token::ConstFloat) => { + self.check_and_eat_token(C1Token::ConstFloat).unwrap(); + Ok(()) + }, + Some(C1Token::ConstBoolean) => { + self.check_and_eat_token(C1Token::ConstBoolean).unwrap(); + Ok(()) + }, + Some(C1Token::Identifier) => { + + if self.lx.peek_token() == Some(C1Token::LeftParenthesis) { + self.functioncall().unwrap(); + }else{ + self.check_and_eat_token(C1Token::Identifier).unwrap(); + } + + Ok(()) + }, + Some(C1Token::LeftParenthesis) => { + + print!("factor left parenthesis->"); + + self.check_and_eat_token(C1Token::LeftParenthesis).unwrap(); + self.assignment().unwrap(); + self.check_and_eat_token(C1Token::RightParenthesis).unwrap(); + Ok(()) + }, + _ => Err(format!("Expected token group 'factor' but found {:?}", self.lx.current_token().unwrap())), + } + + } + + + fn current_matches(&self, token: C1Token) -> ParseResult { + if self.lx.current_token() == Some(token) { + Ok(()) + } else { + Err(format!("Expected token {:?}", token)) + } + } + + fn check_and_eat_token(&mut self, token: C1Token) -> ParseResult{ + println!("Checking token: {:?} with text {:?} in line {:?}", token, self.lx.current_text().unwrap(), self.lx.current_line_number().unwrap()); + match self.lx.current_token() { + Some(x) => { + if x == token { + println!("Correct: {:?}", x); + self.lx.eat(); + return Ok(()); + } + println!("Wrong: {:?}", x); + return Err(format!("Expected token {:?} but found {:?}", token, x)); + }, + None => Err("No token".to_owned()), + } + } +} \ No newline at end of file diff --git a/src/lexer.rs b/src/lexer.rs index a955a4d..e56101b 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -126,6 +126,10 @@ pub enum C1Token { #[regex("//[^\n]*(\n)?", logos::skip)] CPPComment, + #[regex(r"\r", logos::skip)] //NEW + carriagereturn, + + // We can also use this variant to define whitespace, // or any other matches we wish to skip. #[regex(r"[ \t\f]+", logos::skip)] diff --git a/src/lib.rs b/src/lib.rs index 82c0db8..4de0c7a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,3 +10,5 @@ pub use lexer::C1Token; // You will need a re-export of your C1Parser definition. Here is an example: // mod parser; // pub use parser::C1Parser; +mod C1_parser; +pub use C1_parser::C1Parser; diff --git a/tests/parser.rs b/tests/parser.rs index a627444..883b222 100644 --- a/tests/parser.rs +++ b/tests/parser.rs @@ -4,6 +4,9 @@ use std::fs; #[test] fn run_example() { let text = fs::read_to_string("tests/data/beispiel.c-1").unwrap(); + + println!("test1"); + let result = C1Parser::parse(text.as_str()); assert!(result.is_ok(), "Parse result: {}", result.err().unwrap()); } -- GitLab