From 82160936b83a6084a9cd5ba5b6fa728e0a24a050 Mon Sep 17 00:00:00 2001 From: Noah Graf Date: Thu, 25 Sep 2025 16:15:12 -0500 Subject: [PATCH 1/3] New ast format and basic parsing functions --- src/parser.rs | 105 ++++++++--------- src/parser/ast.rs | 234 ++------------------------------------ src/parser/expressions.rs | 90 +++++++++++++++ src/parser/nodes.rs | 41 +++++++ 4 files changed, 194 insertions(+), 276 deletions(-) create mode 100644 src/parser/expressions.rs create mode 100644 src/parser/nodes.rs diff --git a/src/parser.rs b/src/parser.rs index 2925ef7..24957f3 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -7,9 +7,12 @@ use crate::{ Lexer, token::{self, Token}, }, - parser::ast::{ASTBinaryOperator, ASTBinaryOperatorKind, ASTExpression, ASTStatement}, + parser::ast::ExpressionNode, }; pub mod ast; +mod expressions; +mod nodes; +use expressions::*; #[allow(dead_code)] pub struct Parser { @@ -45,66 +48,59 @@ impl Parser { } } - pub fn next_statement(&mut self) -> Option { - self.parse_statement() - } + fn parse_expression(&mut self) -> Option> { + let mut left_expression = self.parse_factor()?; - fn parse_statement(&mut self) -> Option { - //let token = self.current()?; - let expr = self.parse_expression()?; - Some(ASTStatement::expression(expr)) - } + let mut token = self.pop()?; - fn parse_expression(&mut self) -> Option { - self.parse_binary_expression(0) - } - - fn parse_binary_expression(&mut self, precedence: u8) -> Option { - let mut left = self.parse_primary_expression()?; - while let Some(operator) = self.parse_binary_operator() { - self.position += 1; - let operator_precedence = operator.precedence(); - if operator_precedence < precedence { - break; + // while multiplication or divide + while token == token::Token::Plus || token == token::Token::Minus { + let operation = token.clone(); + let next_factor = self.parse_factor()?; + match operation { + Token::Star => { + left_expression = Box::new(MultNode::new(left_expression, next_factor)) + } + Token::Slash => { + left_expression = Box::new(DivNode::new(left_expression, next_factor)) + } + _ => panic!("Unknown factor found"), } - let right: ASTExpression = self.parse_binary_expression(operator_precedence)?; - left = ASTExpression::binary(operator, left, right); + + // grabs next token + token = self.pop()?; } - Some(left) + return Some(left_expression); } - fn parse_binary_operator(&mut self) -> Option { - let token: Token = self.current()?; - let kind: Option = match token { - token::Token::Plus => Some(ASTBinaryOperatorKind::Plus), - token::Token::Minus => Some(ASTBinaryOperatorKind::Minus), - token::Token::Asterisk => Some(ASTBinaryOperatorKind::Mult), - token::Token::Slash => Some(ASTBinaryOperatorKind::Divide), - _ => None, - }; - kind.map(|kind: ASTBinaryOperatorKind| ASTBinaryOperator::new(kind, token.clone())) - } + fn parse_factor(&mut self) -> Option> { + let mut left_factor = self.parse_id()?; - fn parse_primary_expression(&mut self) -> Option { - let token: Token = self.current()?; - // match basic expression types - match token { - token::Token::Integer(int) => { - self.position += 1; - Some(ASTExpression::number(int as f64)) - } - token::Token::LParen => { - self.position += 1; - let expr: ASTExpression = self.parse_expression()?; - let token: Token = self.current()?; - if token != token::Token::RParen { - panic!("Expected Right Parentheses"); - } - self.position += 1; - Some(ASTExpression::paren(expr)) + let mut token = self.pop()?; + + // while multiplication or divide + while token == token::Token::Star || token == token::Token::Slash { + let operation = token.clone(); + let next_factor = self.parse_id()?; + match operation { + Token::Star => left_factor = Box::new(MultNode::new(left_factor, next_factor)), + Token::Slash => left_factor = Box::new(DivNode::new(left_factor, next_factor)), + _ => panic!("Unknown factor found"), } - _ => None, + + // grabs next token + token = self.pop()?; + } + + return Some(left_factor); + } + + fn parse_id(&mut self) -> Option> { + // Current token is right before the id type + match self.pop()? { + Token::Integer(val) => Some(Box::new(IntNode::new(val))), + _ => panic!("Invalid id found"), } } @@ -115,4 +111,9 @@ impl Parser { fn current(&self) -> Option { self.peek(0) } + + fn pop(&mut self) -> Option { + self.position += 1; + self.peek(0) + } } diff --git a/src/parser/ast.rs b/src/parser/ast.rs index cb1d872..221abfe 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -1,237 +1,23 @@ use crate::lexer::token::Token; +use crate::parser::nodes::*; -#[derive(Debug, PartialEq)] -#[allow(clippy::upper_case_acronyms)] -pub struct AST { - pub statements: Vec, +struct Ast { + program: Option, } -#[derive(Debug, PartialEq)] -pub enum ASTStatementKind { - Expression(ASTExpression), -} - -#[derive(Debug, PartialEq)] -pub struct ASTStatement { - kind: ASTStatementKind, -} - -#[derive(Debug, PartialEq)] -pub struct ASTExpression { - kind: ASTExpressionKind, -} - -#[derive(Debug, PartialEq)] -pub enum ASTExpressionKind { - Number(ASTNumberExpression), - Binary(ASTBinaryExpression), - Paren(ASTParenExpression), -} - -#[derive(Debug, PartialEq)] -pub struct ASTBinaryExpression { - left: Box, - operator: ASTBinaryOperator, - right: Box, -} - -#[derive(Debug, PartialEq)] -pub struct ASTBinaryOperator { - kind: ASTBinaryOperatorKind, - token: Token, -} - -#[derive(Debug, PartialEq)] -pub enum ASTBinaryOperatorKind { - Plus, - Minus, - Mult, - Divide, -} - -#[derive(Debug, PartialEq)] -pub struct ASTParenExpression { - expression: Box, -} - -impl ASTBinaryOperator { - pub fn new(kind: ASTBinaryOperatorKind, token: Token) -> Self { - ASTBinaryOperator { kind, token } - } - - pub fn precedence(&self) -> u8 { - match self.kind { - ASTBinaryOperatorKind::Plus => 1, - ASTBinaryOperatorKind::Minus => 1, - ASTBinaryOperatorKind::Divide => 2, - ASTBinaryOperatorKind::Mult => 2, - } - } -} - -#[derive(Debug, PartialEq)] -pub struct ASTNumberExpression { - number: f64, -} - -impl From for ASTNumberExpression { - fn from(value: f64) -> Self { - ASTNumberExpression { number: value } - } -} - -impl ASTStatement { - pub fn new(kind: ASTStatementKind) -> Self { - ASTStatement { kind } - } - - pub fn expression(expr: ASTExpression) -> Self { - ASTStatement::new(ASTStatementKind::Expression(expr)) - } -} - -impl ASTExpression { - pub fn new(kind: ASTExpressionKind) -> Self { - ASTExpression { kind } - } - - pub fn number(number: f64) -> Self { - ASTExpression::new(ASTExpressionKind::Number(ASTNumberExpression { number })) - } - - pub fn binary(operator: ASTBinaryOperator, left: ASTExpression, right: ASTExpression) -> Self { - ASTExpression::new(ASTExpressionKind::Binary(ASTBinaryExpression { - left: Box::new(left), - operator, - right: Box::new(right), - })) - } - - pub fn paren(paren_expression: ASTExpression) -> Self { - ASTExpression::new(ASTExpressionKind::Paren(ASTParenExpression { - expression: Box::new(paren_expression), - })) - } -} - -impl From for ASTExpression { - fn from(value: f64) -> Self { - Self { - kind: ASTExpressionKind::Number(ASTNumberExpression { number: value }), - } - } -} - -#[allow(unused)] -#[allow(dead_code)] -impl AST { +impl Ast { pub fn new() -> Self { - Self { - statements: Vec::new(), - } - } - - pub fn add_statement(&mut self, statement: ASTStatement) { - self.statements.push(statement); - } - - pub fn visit(&mut self, visitor: &mut dyn ASTVisitor) { - for statement in &self.statements { - visitor.visit_statement(statement); - } - } - - pub fn visualize(&mut self) { - let mut printer = ASTPrinter { indent: 0 }; - self.visit(&mut printer); + Ast { program: None } } } -pub trait ASTVisitor { - fn do_visit_statement(&mut self, statement: &ASTStatement) { - match &statement.kind { - ASTStatementKind::Expression(expr) => { - self.visit_expression(expr); - } - } - } +pub trait AstNode { + fn visit_node(&self); - fn visit_statement(&mut self, statement: &ASTStatement) { - self.do_visit_statement(statement); - } - fn do_visit_expression(&mut self, expression: &ASTExpression) { - match &expression.kind { - ASTExpressionKind::Number(num) => { - self.visit_number(num); - } - ASTExpressionKind::Binary(expr) => { - self.visit_binary_expression(expr); - } - ASTExpressionKind::Paren(expr) => { - self.visit_paren_expression(expr); - } - } - } - fn visit_expression(&mut self, expression: &ASTExpression) { - self.do_visit_expression(expression); - } - fn visit_number(&mut self, number: &ASTNumberExpression); - - fn visit_binary_expression(&mut self, binary_expression: &ASTBinaryExpression) { - self.visit_expression(&binary_expression.left); - self.visit_expression(&binary_expression.right); - } - fn visit_paren_expression(&mut self, paren_expr: &ASTParenExpression) { - self.visit_expression(&paren_expr.expression); - } -} - -pub struct ASTPrinter { - indent: usize, -} - -const INDENT_LEVEL: usize = 2; -impl ASTVisitor for ASTPrinter { - fn visit_number(&mut self, number: &ASTNumberExpression) { - self.print_with_indent(&format!("Number: {}", number.number)); - } - - fn visit_statement(&mut self, statement: &ASTStatement) { - self.print_with_indent("Statement"); - self.indent += INDENT_LEVEL; - ASTVisitor::do_visit_statement(self, statement); - self.indent -= INDENT_LEVEL; - } - - fn visit_expression(&mut self, expression: &ASTExpression) { - self.print_with_indent("Expression"); - self.indent += INDENT_LEVEL; - ASTVisitor::do_visit_expression(self, expression); - self.indent -= INDENT_LEVEL; - } - - fn visit_binary_expression(&mut self, binary_expression: &ASTBinaryExpression) { - self.print_with_indent("Binary Expression:"); - self.indent += INDENT_LEVEL; - self.print_with_indent(&format!("Operator {:?}", binary_expression.operator.kind)); - self.visit_expression(&binary_expression.left); - self.visit_expression(&binary_expression.right); - self.indent -= INDENT_LEVEL; - } - - fn visit_paren_expression(&mut self, paren_expr: &ASTParenExpression) { - self.print_with_indent("Parenthesized Expression: "); - self.indent += INDENT_LEVEL; - self.visit_expression(&paren_expr.expression); - self.indent -= INDENT_LEVEL; - } + fn codegen(&self); } -impl ASTPrinter { - fn print_with_indent(&mut self, text: &str) { - println!("{}{}", " ".repeat(self.indent), text); - } -} +pub trait ExpressionNode: AstNode {} #[allow(unused)] mod test { @@ -244,7 +30,7 @@ mod test { #[test] #[timeout(100)] fn test_basic_output() { - let mut ast: AST = AST::new(); + let mut ast: Ast = Ast::new(); let mut lexer: Lexer = Lexer::new("22"); let mut tokens: Vec = lexer.parse_tokens(); let mut parser: Parser = Parser::from_tokens(tokens); diff --git a/src/parser/expressions.rs b/src/parser/expressions.rs new file mode 100644 index 0000000..47f8298 --- /dev/null +++ b/src/parser/expressions.rs @@ -0,0 +1,90 @@ +use crate::parser::ast::{AstNode, ExpressionNode}; + +pub struct PlusNode { + lhs: Box, + rhs: Box, +} + +impl AstNode for PlusNode { + fn codegen(&self) {} + fn visit_node(&self) {} +} + +impl ExpressionNode for PlusNode {} + +impl PlusNode { + pub fn new(lhs: Box, rhs: Box) -> Self { + PlusNode { lhs, rhs } + } +} + +pub struct MinusNode { + lhs: Box, + rhs: Box, +} + +impl AstNode for MinusNode { + fn codegen(&self) {} + fn visit_node(&self) {} +} + +impl ExpressionNode for MinusNode {} + +impl MinusNode { + pub fn new(lhs: Box, rhs: Box) -> Self { + MinusNode { lhs, rhs } + } +} + +pub struct MultNode { + lhs: Box, + rhs: Box, +} + +impl AstNode for MultNode { + fn codegen(&self) {} + fn visit_node(&self) {} +} + +impl ExpressionNode for MultNode {} + +impl MultNode { + pub fn new(lhs: Box, rhs: Box) -> Self { + MultNode { lhs, rhs } + } +} + +pub struct DivNode { + lhs: Box, + rhs: Box, +} + +impl AstNode for DivNode { + fn codegen(&self) {} + fn visit_node(&self) {} +} + +impl ExpressionNode for DivNode {} + +impl DivNode { + pub fn new(lhs: Box, rhs: Box) -> Self { + DivNode { lhs, rhs } + } +} + +pub struct IntNode { + val: i64, +} + +impl AstNode for IntNode { + fn codegen(&self) {} + fn visit_node(&self) {} +} + +impl ExpressionNode for IntNode {} + +impl IntNode { + pub fn new(val: i64) -> Self { + IntNode { val } + } +} diff --git a/src/parser/nodes.rs b/src/parser/nodes.rs new file mode 100644 index 0000000..314c7c8 --- /dev/null +++ b/src/parser/nodes.rs @@ -0,0 +1,41 @@ +use crate::parser::ast::{AstNode, ExpressionNode}; + +pub struct ProgramNode { + main: FunctionNode, +} + +impl AstNode for ProgramNode { + fn visit_node(&self) {} + fn codegen(&self) {} +} + +pub struct Arguments {} + +impl AstNode for Arguments { + fn codegen(&self) {} + fn visit_node(&self) {} +} + +pub struct FunctionNode { + name: String, + arguments: Arguments, + return_type: String, + expr: Box, +} + +impl AstNode for FunctionNode { + fn codegen(&self) {} + fn visit_node(&self) {} +} + +struct AssignNode { + name: String, + expr: Box, +} + +impl AstNode for AssignNode { + fn visit_node(&self) {} + fn codegen(&self) {} +} + +impl ExpressionNode for AssignNode {} From dc0696fa74994819ed1320fef14817cce2b2bf64 Mon Sep 17 00:00:00 2001 From: Noah Graf Date: Thu, 25 Sep 2025 16:29:06 -0500 Subject: [PATCH 2/3] Added error type git push --- src/error.rs | 12 +++++++++++ src/lexer/token.rs | 12 +++++++++++ src/main.rs | 1 + src/parser.rs | 53 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+) create mode 100644 src/error.rs diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..3f613fe --- /dev/null +++ b/src/error.rs @@ -0,0 +1,12 @@ +#[derive(Debug)] +pub enum BcompError { + ParseError(String), +} + +impl std::fmt::Display for BcompError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Generic error occurred") + } +} + +impl std::error::Error for BcompError {} diff --git a/src/lexer/token.rs b/src/lexer/token.rs index 4a93282..a8e3c57 100644 --- a/src/lexer/token.rs +++ b/src/lexer/token.rs @@ -73,4 +73,16 @@ impl Token { _ => panic!("Not Identifier!"), } } + + /// Informs on if the current toekn is a comparison token + pub fn is_comparison(&self) -> bool { + match *self { + Self::Equal => true, + Self::Less => true, + Self::LessEqual => true, + Self::Greater => true, + Self::GreaterEqual => true, + _ => false, + } + } } diff --git a/src/main.rs b/src/main.rs index 886cb74..b9bd242 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ mod emitter; +mod error; mod lexer; mod parser; diff --git a/src/parser.rs b/src/parser.rs index 24957f3..8ea7db4 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -3,6 +3,7 @@ //! This is one of the harder modules to create as I am not familiar with it at all //! Do not be afraid to modify any of the strucutre I have laid out here use crate::{ + error::BcompError, lexer::{ Lexer, token::{self, Token}, @@ -48,6 +49,46 @@ impl Parser { } } + /// Parses a comparison as a top level expression, since in the order of operations comparisons happen last + fn parse_comparison(&mut self) -> Option> { + let mut left_side = self.parse_expression()?; + + let mut token = self.pop()?; + if token.is_comparison() { + // saves the current operation + let operation = token.clone(); + + let right_side = self.parse_expression(); + } + + None + // // std::cout << "attempting to build comparison with token " << token + // // << std::endl; + // Expression left = build_expression_node(); + // // if (token != ';' && token != '}' && token != IN && token != ')') { + // // token = nextToken(); + // // } + // if (token == LESS || token == LE || token == EQL) { + // int operation = token; + // token = nextToken(); + // Expression right = build_expression_node(); + // // token = nextToken(); + // expect_not(LESS, "syntax error"); + // expect_not(LE, "syntax error"); + // expect_not(EQL, "syntax error"); + // if (operation == LESS) { + // return lt(left, right); + // } else if (operation == LE) { + // return leq(left, right); + // } else if (operation == EQL) { + // return eq(left, right); + // } + // } + // // std::cout << "Completing building a single expression with token " << token + // // << std::endl; + // return left; + } + fn parse_expression(&mut self) -> Option> { let mut left_expression = self.parse_factor()?; @@ -112,8 +153,20 @@ impl Parser { self.peek(0) } + /// Gets the next token an incriments the current position fn pop(&mut self) -> Option { self.position += 1; self.peek(0) } + + fn expect(&self, token: token::Token) -> Result<(), BcompError> { + if self.current() != Some(token) { + Err(BcompError::ParseError(format!( + "Invalid token found at location {}", + self.position + ))) + } else { + Ok(()) + } + } } From 0f80444cc7720e7ba38199e4982d9b1d737d7d2a Mon Sep 17 00:00:00 2001 From: Noah Graf Date: Thu, 25 Sep 2025 16:41:29 -0500 Subject: [PATCH 3/3] Added comparison node --- src/parser.rs | 51 +++++++++------------- src/parser/expressions.rs | 90 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+), 31 deletions(-) diff --git a/src/parser.rs b/src/parser.rs index 8ea7db4..de7a820 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2,6 +2,8 @@ //! //! This is one of the harder modules to create as I am not familiar with it at all //! Do not be afraid to modify any of the strucutre I have laid out here +use core::panic; + use crate::{ error::BcompError, lexer::{ @@ -51,42 +53,28 @@ impl Parser { /// Parses a comparison as a top level expression, since in the order of operations comparisons happen last fn parse_comparison(&mut self) -> Option> { - let mut left_side = self.parse_expression()?; + let left_side = self.parse_expression()?; let mut token = self.pop()?; if token.is_comparison() { // saves the current operation let operation = token.clone(); - let right_side = self.parse_expression(); - } + let right_side = self.parse_expression()?; + token = self.pop()?; - None - // // std::cout << "attempting to build comparison with token " << token - // // << std::endl; - // Expression left = build_expression_node(); - // // if (token != ';' && token != '}' && token != IN && token != ')') { - // // token = nextToken(); - // // } - // if (token == LESS || token == LE || token == EQL) { - // int operation = token; - // token = nextToken(); - // Expression right = build_expression_node(); - // // token = nextToken(); - // expect_not(LESS, "syntax error"); - // expect_not(LE, "syntax error"); - // expect_not(EQL, "syntax error"); - // if (operation == LESS) { - // return lt(left, right); - // } else if (operation == LE) { - // return leq(left, right); - // } else if (operation == EQL) { - // return eq(left, right); - // } - // } - // // std::cout << "Completing building a single expression with token " << token - // // << std::endl; - // return left; + // Match what our operation was + Some(match operation { + Token::Less => Box::new(LessNode::new(left_side, right_side)), + Token::LessEqual => Box::new(LessEqualNode::new(left_side, right_side)), + Token::Equal => Box::new(EqualNode::new(left_side, right_side)), + Token::Greater => Box::new(GreaterNode::new(left_side, right_side)), + Token::GreaterEqual => Box::new(GreaterEqualNode::new(left_side, right_side)), + _ => panic!("Invalid operation provided"), + }) + } else { + None + } } fn parse_expression(&mut self) -> Option> { @@ -112,7 +100,7 @@ impl Parser { token = self.pop()?; } - return Some(left_expression); + Some(left_expression) } fn parse_factor(&mut self) -> Option> { @@ -134,7 +122,7 @@ impl Parser { token = self.pop()?; } - return Some(left_factor); + Some(left_factor) } fn parse_id(&mut self) -> Option> { @@ -161,6 +149,7 @@ impl Parser { fn expect(&self, token: token::Token) -> Result<(), BcompError> { if self.current() != Some(token) { + panic!("Uh oh"); Err(BcompError::ParseError(format!( "Invalid token found at location {}", self.position diff --git a/src/parser/expressions.rs b/src/parser/expressions.rs index 47f8298..5da170c 100644 --- a/src/parser/expressions.rs +++ b/src/parser/expressions.rs @@ -54,6 +54,96 @@ impl MultNode { } } +pub struct LessNode { + lhs: Box, + rhs: Box, +} + +impl AstNode for LessNode { + fn codegen(&self) {} + fn visit_node(&self) {} +} + +impl ExpressionNode for LessNode {} + +impl LessNode { + pub fn new(lhs: Box, rhs: Box) -> Self { + LessNode { lhs, rhs } + } +} + +pub struct LessEqualNode { + lhs: Box, + rhs: Box, +} + +impl AstNode for LessEqualNode { + fn codegen(&self) {} + fn visit_node(&self) {} +} + +impl ExpressionNode for LessEqualNode {} + +impl LessEqualNode { + pub fn new(lhs: Box, rhs: Box) -> Self { + LessEqualNode { lhs, rhs } + } +} + +pub struct EqualNode { + lhs: Box, + rhs: Box, +} + +impl AstNode for EqualNode { + fn codegen(&self) {} + fn visit_node(&self) {} +} + +impl ExpressionNode for EqualNode {} + +impl EqualNode { + pub fn new(lhs: Box, rhs: Box) -> Self { + EqualNode { lhs, rhs } + } +} + +pub struct GreaterNode { + lhs: Box, + rhs: Box, +} + +impl AstNode for GreaterNode { + fn codegen(&self) {} + fn visit_node(&self) {} +} + +impl ExpressionNode for GreaterNode {} + +impl GreaterNode { + pub fn new(lhs: Box, rhs: Box) -> Self { + GreaterNode { lhs, rhs } + } +} + +pub struct GreaterEqualNode { + lhs: Box, + rhs: Box, +} + +impl AstNode for GreaterEqualNode { + fn codegen(&self) {} + fn visit_node(&self) {} +} + +impl ExpressionNode for GreaterEqualNode {} + +impl GreaterEqualNode { + pub fn new(lhs: Box, rhs: Box) -> Self { + GreaterEqualNode { lhs, rhs } + } +} + pub struct DivNode { lhs: Box, rhs: Box,