An error occurred while loading the file. Please try again.
-
freidlan@informatik.hu-berlin.de authored891f0b3d
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
parser.rs 8.44 KiB
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)
}
}