mirror of
https://github.com/Noratrieb/uwucc.git
synced 2026-01-14 16:45:07 +01:00
a little bit of expr parsing
This commit is contained in:
parent
bf2ea3f7f4
commit
56974cf077
4 changed files with 186 additions and 2 deletions
|
|
@ -5,6 +5,60 @@ use dbg_pls::DebugPls;
|
||||||
|
|
||||||
use crate::Spanned;
|
use crate::Spanned;
|
||||||
|
|
||||||
|
//
|
||||||
|
// --- Expr
|
||||||
|
//
|
||||||
|
|
||||||
|
#[derive(Debug, DebugPls)]
|
||||||
|
pub enum Atom {
|
||||||
|
Ident(String),
|
||||||
|
Int(i128),
|
||||||
|
Float(f64),
|
||||||
|
String(String),
|
||||||
|
Char(u8),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, DebugPls)]
|
||||||
|
pub enum UnaryOp {
|
||||||
|
AddrOf,
|
||||||
|
Deref,
|
||||||
|
Plus,
|
||||||
|
Minus,
|
||||||
|
Tilde,
|
||||||
|
Bang,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, DebugPls)]
|
||||||
|
pub enum BinaryOp {
|
||||||
|
Add,
|
||||||
|
Sub,
|
||||||
|
Comma,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, DebugPls)]
|
||||||
|
pub struct ExprUnary {
|
||||||
|
pub rhs: Box<Spanned<Expr>>,
|
||||||
|
pub op: UnaryOp,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, DebugPls)]
|
||||||
|
pub struct ExprBinary {
|
||||||
|
pub lhs: Box<Spanned<Expr>>,
|
||||||
|
pub rhs: Box<Spanned<Expr>>,
|
||||||
|
pub op: BinaryOp,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, DebugPls)]
|
||||||
|
pub enum Expr {
|
||||||
|
Atom(Atom),
|
||||||
|
Unary(ExprUnary),
|
||||||
|
Binary(ExprBinary),
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// --- Types and decls and garbage whatever
|
||||||
|
//
|
||||||
|
|
||||||
#[derive(Debug, DebugPls)]
|
#[derive(Debug, DebugPls)]
|
||||||
pub enum TypeSpecifier {
|
pub enum TypeSpecifier {
|
||||||
Void,
|
Void,
|
||||||
|
|
@ -59,7 +113,7 @@ pub enum Decl {
|
||||||
#[derive(Debug, DebugPls)]
|
#[derive(Debug, DebugPls)]
|
||||||
pub struct InitDecl {
|
pub struct InitDecl {
|
||||||
pub declarator: Declarator,
|
pub declarator: Declarator,
|
||||||
pub init: Option<()>,
|
pub init: Option<Expr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, DebugPls)]
|
#[derive(Debug, DebugPls)]
|
||||||
|
|
@ -92,7 +146,7 @@ pub struct Declarator {
|
||||||
#[derive(Debug, DebugPls)]
|
#[derive(Debug, DebugPls)]
|
||||||
pub struct FunctionDef {
|
pub struct FunctionDef {
|
||||||
pub declaration: Decl,
|
pub declaration: Decl,
|
||||||
pub body: Vec<()>,
|
pub body: Vec<Expr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, DebugPls)]
|
#[derive(Debug, DebugPls)]
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ use crate::{
|
||||||
Span, Spanned,
|
Span, Spanned,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mod expr;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ParserError {
|
pub struct ParserError {
|
||||||
span: Span,
|
span: Span,
|
||||||
|
|
|
||||||
124
parser/src/parser/expr.rs
Normal file
124
parser/src/parser/expr.rs
Normal file
|
|
@ -0,0 +1,124 @@
|
||||||
|
//! The expression parser is implemented as a pratt parser.
|
||||||
|
//!
|
||||||
|
//! For more information, see https://matklad.github.io/2020/04/13/simple-but-powerful-pratt-parsing.html
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
ast::{Atom, BinaryOp, Expr, ExprBinary, ExprUnary, UnaryOp},
|
||||||
|
parser::{Parser, ParserError, Result},
|
||||||
|
pre::Punctuator as P,
|
||||||
|
token::{Constant, Token as Tok},
|
||||||
|
Span, Spanned,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl<'src, I> Parser<'src, I>
|
||||||
|
where
|
||||||
|
I: Iterator<Item = (Tok<'src>, Span)>,
|
||||||
|
{
|
||||||
|
pub fn expr(&mut self) -> Result<Spanned<Expr>> {
|
||||||
|
self.expr_bp(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_lhs(&mut self) -> Result<Spanned<Expr>> {
|
||||||
|
let (typ, span) = match self.peek_t()? {
|
||||||
|
(Tok::Ident(ident), span) => (Atom::Ident(ident.to_string()), span),
|
||||||
|
(Tok::StringLiteral(literal), span) => (Atom::String(literal.to_string()), span),
|
||||||
|
(Tok::Constant(Constant::Int(int)), span) => (Atom::Int(*int), span),
|
||||||
|
(Tok::Constant(Constant::Float(float)), span) => (Atom::Float(*float), span),
|
||||||
|
(Tok::Constant(Constant::Char(char)), span) => (Atom::Char(*char), span),
|
||||||
|
&(Tok::Punct(punct), span) => {
|
||||||
|
let r_bp = prefix_binding_power(&Tok::Punct(punct));
|
||||||
|
let op = unary_op_from_token(&Tok::Punct(punct), span)?;
|
||||||
|
let rhs = self.expr_bp(r_bp)?;
|
||||||
|
|
||||||
|
return Ok((
|
||||||
|
Expr::Unary(ExprUnary {
|
||||||
|
rhs: Box::new(rhs),
|
||||||
|
op,
|
||||||
|
}),
|
||||||
|
span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
(tok, span) => {
|
||||||
|
return Err(ParserError::new(
|
||||||
|
*span,
|
||||||
|
format!("expected expression, found {tok}"),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((Expr::Atom(typ), *span))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expr_bp(&mut self, min_bp: u8) -> Result<Spanned<Expr>> {
|
||||||
|
let mut lhs = self.get_lhs()?;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let (tok, span) = match self.next_t() {
|
||||||
|
Ok(tok) => tok,
|
||||||
|
Err(_) => break,
|
||||||
|
};
|
||||||
|
let op = binary_op_from_token(&tok, span)?;
|
||||||
|
|
||||||
|
let (l_bp, r_bp) = infix_binding_power(&tok);
|
||||||
|
if l_bp < min_bp {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let rhs = self.expr_bp(r_bp)?;
|
||||||
|
|
||||||
|
let span = lhs.1.extend(rhs.1);
|
||||||
|
|
||||||
|
lhs = (
|
||||||
|
Expr::Binary(ExprBinary {
|
||||||
|
lhs: Box::new(lhs),
|
||||||
|
rhs: Box::new(rhs),
|
||||||
|
op,
|
||||||
|
}),
|
||||||
|
span,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unary_op_from_token(tok: &Tok<'_>, span: Span) -> Result<UnaryOp> {
|
||||||
|
match tok {
|
||||||
|
Tok::Punct(P::Ampersand) => Ok(UnaryOp::AddrOf),
|
||||||
|
Tok::Punct(P::Asterisk) => Ok(UnaryOp::Deref),
|
||||||
|
Tok::Punct(P::Plus) => Ok(UnaryOp::Plus),
|
||||||
|
Tok::Punct(P::Minus) => Ok(UnaryOp::Minus),
|
||||||
|
Tok::Punct(P::Tilde) => Ok(UnaryOp::Tilde),
|
||||||
|
Tok::Punct(P::Bang) => Ok(UnaryOp::Bang),
|
||||||
|
_ => Err(ParserError::new(
|
||||||
|
span,
|
||||||
|
format!("invalid unary operation: {tok}"),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn binary_op_from_token(tok: &Tok<'_>, span: Span) -> Result<BinaryOp> {
|
||||||
|
match tok {
|
||||||
|
Tok::Punct(P::Plus) => Ok(BinaryOp::Add),
|
||||||
|
Tok::Punct(P::Minus) => Ok(BinaryOp::Sub),
|
||||||
|
_ => Err(ParserError::new(
|
||||||
|
span,
|
||||||
|
format!("invalid binary operation: {tok}"),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prefix_binding_power(tok: &Tok<'_>) -> u8 {
|
||||||
|
match tok {
|
||||||
|
Tok::Punct(P::Ampersand | P::Asterisk | P::Plus | P::Minus | P::Tilde | P::Bang) => 255,
|
||||||
|
_ => panic!("invalid token in expression! {tok:?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn infix_binding_power(tok: &Tok<'_>) -> (u8, u8) {
|
||||||
|
match tok {
|
||||||
|
Tok::Punct(P::Comma) => (1, 2),
|
||||||
|
Tok::Punct(P::Plus | P::Minus) => (3, 4),
|
||||||
|
Tok::Punct(P::Asterisk | P::Slash) => (5, 6),
|
||||||
|
_ => panic!("invalid token in expression! {tok:?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -55,6 +55,8 @@ pub enum Punctuator {
|
||||||
Tilde,
|
Tilde,
|
||||||
/// ! 🤯
|
/// ! 🤯
|
||||||
Bang,
|
Bang,
|
||||||
|
/// /
|
||||||
|
Slash,
|
||||||
//// %
|
//// %
|
||||||
Percent,
|
Percent,
|
||||||
/// <<
|
/// <<
|
||||||
|
|
@ -138,6 +140,7 @@ impl Display for Punctuator {
|
||||||
Punctuator::Minus => f.write_str("-"),
|
Punctuator::Minus => f.write_str("-"),
|
||||||
Punctuator::Tilde => f.write_str("~"),
|
Punctuator::Tilde => f.write_str("~"),
|
||||||
Punctuator::Bang => f.write_str("!"),
|
Punctuator::Bang => f.write_str("!"),
|
||||||
|
Punctuator::Slash => f.write_str("/"),
|
||||||
Punctuator::Percent => f.write_str("%"),
|
Punctuator::Percent => f.write_str("%"),
|
||||||
Punctuator::LeftLeftChevron => f.write_str("<<"),
|
Punctuator::LeftLeftChevron => f.write_str("<<"),
|
||||||
Punctuator::RightRightChevron => f.write_str(">>"),
|
Punctuator::RightRightChevron => f.write_str(">>"),
|
||||||
|
|
@ -383,6 +386,7 @@ where
|
||||||
(b'-', _, _) => break (TokP(Punctuator::Minus), start_span),
|
(b'-', _, _) => break (TokP(Punctuator::Minus), start_span),
|
||||||
(b'~', _, _) => break (TokP(Punctuator::Tilde), start_span),
|
(b'~', _, _) => break (TokP(Punctuator::Tilde), start_span),
|
||||||
(b'!', _, _) => break (TokP(Punctuator::Bang), start_span),
|
(b'!', _, _) => break (TokP(Punctuator::Bang), start_span),
|
||||||
|
(b'/', _, _) => break (TokP(Punctuator::Slash), start_span),
|
||||||
(b'%', _, _) => break (TokP(Punctuator::Percent), start_span),
|
(b'%', _, _) => break (TokP(Punctuator::Percent), start_span),
|
||||||
(b'<', _, _) => break (TokP(Punctuator::LeftChevron), start_span),
|
(b'<', _, _) => break (TokP(Punctuator::LeftChevron), start_span),
|
||||||
(b'>', _, _) => break (TokP(Punctuator::RightChevron), start_span),
|
(b'>', _, _) => break (TokP(Punctuator::RightChevron), start_span),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue