c_expr/
lib.rs

1#![feature(type_name_of_val)]
2#![feature(or_patterns)]
3use std::any::type_name_of_val;
4
5use logos::{Lexer, Logos};
6
7#[derive(Logos, Debug, Copy, Clone, PartialEq)]
8enum Token {
9    #[regex(r"[a-zA-Z_][\w_]*")]
10    Ident,
11
12    #[regex(r"\d+")]
13    #[regex(r"\d+[uU]")]
14    #[regex(r"\d+[lL]")]
15    #[regex(r"\d+[uU][lL]")]
16    #[regex(r"\d+[uU][lL][lL]")]
17    Num,
18
19    #[regex(r"\d+\.\d*f?")]
20    Real,
21
22    #[regex(r"[\[\{\(]")]
23    LDelim,
24    #[regex(r"[\]\}\)]")]
25    RDelim,
26
27    #[token("->")]
28    Access,
29    #[token("&&")]
30    And,
31    #[token("||")]
32    Or,
33    #[token(">>")]
34    Shr,
35    #[token("<<")]
36    Shl,
37    #[token("==")]
38    Eq,
39    #[token("!=")]
40    Ne,
41    #[token("<=")]
42    Le,
43    #[token(">=")]
44    Ge,
45
46    #[token("++")]
47    Inc,
48    #[token("--")]
49    Dec,
50
51    #[regex(r"[~!&|^=?.,;:*/%+-]", |it| it.slice().as_bytes()[0] as char)]
52    Punct(char),
53
54    #[error]
55    #[regex(r"[ \t\n\f]+", logos::skip)]
56    Error,
57}
58
59impl Token {
60    fn op(self) -> Binop {
61        use Token::*;
62        match self {
63            Access => Binop::PtrField,
64            Punct('.') => Binop::Field,
65            Punct('*') => Binop::Mul,
66            Punct('/') => Binop::Div,
67            Punct('%') => Binop::Rem,
68            Punct('+') => Binop::Add,
69            Punct('-') => Binop::Sub,
70            Shr => Binop::Shl,
71            Shr => Binop::Shr,
72            Le => Binop::Le,
73            Ge => Binop::Ge,
74            Punct('<') => Binop::Lt,
75            Punct('>') => Binop::Gt,
76            Eq => Binop::Eq,
77            Ne => Binop::Ne,
78            Punct('&') => Binop::And,
79            Punct('^') => Binop::Xor,
80            Punct('|') => Binop::Or,
81            And => Binop::Logand,
82            Or => Binop::Logor,
83            _ => unreachable!(),
84        }
85    }
86
87    fn prec(self) -> u32 {
88        use Token::*;
89        match self {
90            Access | Punct('.') => 11,
91            Punct('*' | '/' | '%') => 10,
92            Punct('+' | '-') => 9,
93            Shr | Shl => 8,
94            Le | Ge | Punct('>' | '<') => 7,
95            Eq | Ne => 6,
96            Punct('&') => 5,
97            Punct('^') => 4,
98            Punct('|') => 3,
99            And => 2,
100            Or => 1,
101            _ => 0,
102        }
103    }
104}
105
106#[derive(Debug, Clone, Copy)]
107pub enum Unop {
108    Neg,
109    Not,
110    Flip,
111    PostInc,
112    PostDec,
113    PreInc,
114    PreDec,
115}
116
117#[derive(Debug, Clone, Copy)]
118pub enum Binop {
119    Field,
120    PtrField,
121    Add,
122    Sub,
123    Mul,
124    Div,
125    Rem,
126    And,
127    Xor,
128    Or,
129    Shr,
130    Shl,
131    Eq,
132    Ne,
133    Le,
134    Ge,
135    Lt,
136    Gt,
137    Logand,
138    Logor,
139    Subs,
140}
141
142#[derive(Debug, Clone, Copy)]
143pub enum Suffix {
144    U,
145    UL,
146    ULL,
147    I,
148    L,
149    LL,
150}
151
152#[derive(Debug, Clone)]
153pub enum Expr {
154    Var(String),
155    Num(u64, Suffix),
156    Real(f64),
157    Unary(Unop, Box<Expr>),
158    Binop(Binop, Box<Expr>, Box<Expr>),
159}
160
161#[derive(Debug, Clone, Copy)]
162pub enum Value {
163    Uint(u64),
164    Sint(i64),
165    Real(f64),
166    Bool(bool),
167}
168
169impl Expr {
170    pub fn new(s: &str) -> Option<Expr> {
171        parse_expr(&mut Token::lexer(s)).ok()
172    }
173}
174
175fn check_postfix(it: &mut Lexer<Token>, x: Expr) -> Result<Expr, ()> {
176    use Token::*;
177    Ok(match it.clone().next() {
178        Some(Punct('[')) => {
179            it.next();
180            let y = parse_expr(it)?;
181            match it.next() {
182                Some(Punct(']')) => Expr::Binop(Binop::Subs, Box::new(x), Box::new(y)),
183                _ => return Err(()),
184            }
185        }
186        Some(Inc) => Expr::Unary(Unop::PostInc, Box::new(x)),
187        Some(Dec) => Expr::Unary(Unop::PostDec, Box::new(x)),
188        _ => x,
189    })
190}
191
192fn parse_term(it: &mut Lexer<Token>) -> Result<Expr, ()> {
193    use Token::*;
194    let x = match it.next().ok_or(())? {
195        Ident => Expr::Var(it.slice().to_owned()),
196        Num => {
197            let s: &str = it.slice();
198            let mut cc = s.len();
199            let mut v = String::with_capacity(4);
200            while !(s.as_bytes()[cc - 1] as char).is_digit(10) {
201                v.push(s.as_bytes()[cc - 1].to_ascii_lowercase() as char);
202                cc -= 1;
203            }
204            let ss = match v.as_str() {
205                "llu" => Suffix::ULL,
206                "ll" => Suffix::LL,
207                "lu" => Suffix::UL,
208                "l" => Suffix::L,
209                "u" => Suffix::U,
210                _ => Suffix::I,
211            };
212            Expr::Num(it.slice()[..cc].parse().unwrap(), ss)
213        }
214        Real => Expr::Real(it.slice().replace("f", "").parse().unwrap()),
215        LDelim => {
216            let x = parse_expr(it)?;
217            match it.next() {
218                Some(RDelim) => x,
219                _ => return Err(()),
220            }
221        }
222        Punct('~') => Expr::Unary(Unop::Flip, Box::new(parse_term(it)?)),
223        Punct('!') => Expr::Unary(Unop::Not, Box::new(parse_term(it)?)),
224        Punct('-') => Expr::Unary(Unop::Neg, Box::new(parse_term(it)?)),
225        Inc => Expr::Unary(Unop::PreInc, Box::new(parse_term(it)?)),
226        Dec => Expr::Unary(Unop::PreDec, Box::new(parse_term(it)?)),
227        _ => return Err(()),
228    };
229    check_postfix(it, x)
230}
231
232/*
233expr = precn
234...
235prec1 = prec0 | prec1 + prec0
236prec0 = term | prec0 * term
237term = num | ( expr )
238*/
239
240fn parse_prec(it: &mut Lexer<Token>, mut lhs: Expr, prec: u32) -> Result<Expr, ()> {
241    while it.clone().next().map(|t| t.prec() >= prec) == Some(true) {
242        let t: Token = it.next().unwrap();
243        let prec2 = t.prec();
244        let mut rhs = parse_term(it)?;
245        while it.clone().next().map(|t| t.prec() >= prec2) == Some(true) {
246            rhs = parse_prec(it, rhs, prec + 1)?;
247        }
248        lhs = Expr::Binop(t.op(), Box::new(lhs), Box::new(rhs));
249    }
250
251    Ok(lhs)
252}
253
254fn parse_expr(it: &mut Lexer<Token>) -> Result<Expr, ()> {
255    let x = parse_term(it)?;
256    parse_prec(it, x, 1)
257}
258
259#[test]
260fn tests() {
261    Expr::new("(rasterizationSamples + 31) / 32").unwrap();
262    Expr::new("9 / 2 + a-b").unwrap();
263    Expr::new("abc->abc + abc.abc - x12 * 12").unwrap();
264    Expr::new("(~0U-2)").unwrap();
265    println!("{:?}", Expr::new("(~0U-2)").unwrap());
266}