Skip to main content

libperl_macrogen/
pp_expr.rs

1//! プリプロセッサ条件式の評価
2//!
3//! #if / #elif ディレクティブの条件式を評価する。
4
5use crate::error::{CompileError, PPError};
6use crate::intern::{InternedStr, StringInterner};
7use crate::macro_def::MacroTable;
8use crate::source::SourceLocation;
9use crate::token::{Token, TokenKind};
10
11/// プリプロセッサ式評価器
12pub struct PPExprEvaluator<'a> {
13    tokens: &'a [Token],
14    pos: usize,
15    interner: &'a StringInterner,
16    macros: &'a MacroTable,
17    loc: SourceLocation,
18    /// "defined" キーワードのインターン済み文字列
19    defined_id: Option<InternedStr>,
20}
21
22impl<'a> PPExprEvaluator<'a> {
23    /// 新しい評価器を作成
24    pub fn new(
25        tokens: &'a [Token],
26        interner: &'a StringInterner,
27        macros: &'a MacroTable,
28        loc: SourceLocation,
29    ) -> Self {
30        // "defined" を検索
31        let defined_id = interner.lookup("defined");
32
33        Self {
34            tokens,
35            pos: 0,
36            interner,
37            macros,
38            loc,
39            defined_id,
40        }
41    }
42
43    /// 条件式を評価
44    pub fn evaluate(&mut self) -> Result<i64, CompileError> {
45        let result = self.expr()?;
46        Ok(result)
47    }
48
49    /// 現在のトークンを取得
50    fn current(&self) -> Option<&Token> {
51        self.tokens.get(self.pos)
52    }
53
54    /// 現在のトークン種別を取得
55    fn current_kind(&self) -> Option<&TokenKind> {
56        self.current().map(|t| &t.kind)
57    }
58
59    /// 次へ進む
60    fn advance(&mut self) {
61        if self.pos < self.tokens.len() {
62            self.pos += 1;
63        }
64    }
65
66    /// エラーを生成
67    fn error(&self, msg: &str) -> CompileError {
68        CompileError::Preprocess {
69            loc: self.loc.clone(),
70            kind: PPError::InvalidCondition(msg.to_string()),
71        }
72    }
73
74    /// 条件式 (ternary)
75    fn expr(&mut self) -> Result<i64, CompileError> {
76        let cond = self.logical_or()?;
77
78        if matches!(self.current_kind(), Some(TokenKind::Question)) {
79            self.advance();
80            let then_val = self.expr()?;
81            if !matches!(self.current_kind(), Some(TokenKind::Colon)) {
82                return Err(self.error("expected ':' in ternary expression"));
83            }
84            self.advance();
85            let else_val = self.expr()?;
86            Ok(if cond != 0 { then_val } else { else_val })
87        } else {
88            Ok(cond)
89        }
90    }
91
92    /// 論理OR
93    fn logical_or(&mut self) -> Result<i64, CompileError> {
94        let mut left = self.logical_and()?;
95
96        while matches!(self.current_kind(), Some(TokenKind::PipePipe)) {
97            self.advance();
98            let right = self.logical_and()?;
99            left = if left != 0 || right != 0 { 1 } else { 0 };
100        }
101
102        Ok(left)
103    }
104
105    /// 論理AND
106    fn logical_and(&mut self) -> Result<i64, CompileError> {
107        let mut left = self.bitwise_or()?;
108
109        while matches!(self.current_kind(), Some(TokenKind::AmpAmp)) {
110            self.advance();
111            let right = self.bitwise_or()?;
112            left = if left != 0 && right != 0 { 1 } else { 0 };
113        }
114
115        Ok(left)
116    }
117
118    /// ビットOR
119    fn bitwise_or(&mut self) -> Result<i64, CompileError> {
120        let mut left = self.bitwise_xor()?;
121
122        while matches!(self.current_kind(), Some(TokenKind::Pipe)) {
123            self.advance();
124            let right = self.bitwise_xor()?;
125            left |= right;
126        }
127
128        Ok(left)
129    }
130
131    /// ビットXOR
132    fn bitwise_xor(&mut self) -> Result<i64, CompileError> {
133        let mut left = self.bitwise_and()?;
134
135        while matches!(self.current_kind(), Some(TokenKind::Caret)) {
136            self.advance();
137            let right = self.bitwise_and()?;
138            left ^= right;
139        }
140
141        Ok(left)
142    }
143
144    /// ビットAND
145    fn bitwise_and(&mut self) -> Result<i64, CompileError> {
146        let mut left = self.equality()?;
147
148        while matches!(self.current_kind(), Some(TokenKind::Amp)) {
149            self.advance();
150            let right = self.equality()?;
151            left &= right;
152        }
153
154        Ok(left)
155    }
156
157    /// 等価比較
158    fn equality(&mut self) -> Result<i64, CompileError> {
159        let mut left = self.relational()?;
160
161        loop {
162            match self.current_kind() {
163                Some(TokenKind::EqEq) => {
164                    self.advance();
165                    let right = self.relational()?;
166                    left = if left == right { 1 } else { 0 };
167                }
168                Some(TokenKind::BangEq) => {
169                    self.advance();
170                    let right = self.relational()?;
171                    left = if left != right { 1 } else { 0 };
172                }
173                _ => break,
174            }
175        }
176
177        Ok(left)
178    }
179
180    /// 関係比較
181    fn relational(&mut self) -> Result<i64, CompileError> {
182        let mut left = self.shift()?;
183
184        loop {
185            match self.current_kind() {
186                Some(TokenKind::Lt) => {
187                    self.advance();
188                    let right = self.shift()?;
189                    left = if left < right { 1 } else { 0 };
190                }
191                Some(TokenKind::Gt) => {
192                    self.advance();
193                    let right = self.shift()?;
194                    left = if left > right { 1 } else { 0 };
195                }
196                Some(TokenKind::LtEq) => {
197                    self.advance();
198                    let right = self.shift()?;
199                    left = if left <= right { 1 } else { 0 };
200                }
201                Some(TokenKind::GtEq) => {
202                    self.advance();
203                    let right = self.shift()?;
204                    left = if left >= right { 1 } else { 0 };
205                }
206                _ => break,
207            }
208        }
209
210        Ok(left)
211    }
212
213    /// シフト演算
214    fn shift(&mut self) -> Result<i64, CompileError> {
215        let mut left = self.additive()?;
216
217        loop {
218            match self.current_kind() {
219                Some(TokenKind::LtLt) => {
220                    self.advance();
221                    let right = self.additive()?;
222                    // シフト量はマスクする (TinyCC gen_opic の
223                    // `l1 <<= (l2 & shm)` と同方針)。C ではシフト量 >= 幅は
224                    // UB だが、perl 5.44 のヘッダに評価時 64 以上になる
225                    // #if 式が存在し、panic (shift overflow) してはならない
226                    left = left.wrapping_shl((right & 63) as u32);
227                }
228                Some(TokenKind::GtGt) => {
229                    self.advance();
230                    let right = self.additive()?;
231                    // i64 の >> は算術シフト = TinyCC の TOK_SAR 相当
232                    left >>= (right & 63) as u32;
233                }
234                _ => break,
235            }
236        }
237
238        Ok(left)
239    }
240
241    /// 加減算
242    fn additive(&mut self) -> Result<i64, CompileError> {
243        let mut left = self.multiplicative()?;
244
245        loop {
246            match self.current_kind() {
247                Some(TokenKind::Plus) => {
248                    self.advance();
249                    let right = self.multiplicative()?;
250                    left = left.wrapping_add(right);
251                }
252                Some(TokenKind::Minus) => {
253                    self.advance();
254                    let right = self.multiplicative()?;
255                    left = left.wrapping_sub(right);
256                }
257                _ => break,
258            }
259        }
260
261        Ok(left)
262    }
263
264    /// 乗除算
265    fn multiplicative(&mut self) -> Result<i64, CompileError> {
266        let mut left = self.unary()?;
267
268        loop {
269            match self.current_kind() {
270                Some(TokenKind::Star) => {
271                    self.advance();
272                    let right = self.unary()?;
273                    left = left.wrapping_mul(right);
274                }
275                Some(TokenKind::Slash) => {
276                    self.advance();
277                    let right = self.unary()?;
278                    if right == 0 {
279                        return Err(self.error("division by zero"));
280                    }
281                    left /= right;
282                }
283                Some(TokenKind::Percent) => {
284                    self.advance();
285                    let right = self.unary()?;
286                    if right == 0 {
287                        return Err(self.error("modulo by zero"));
288                    }
289                    left %= right;
290                }
291                _ => break,
292            }
293        }
294
295        Ok(left)
296    }
297
298    /// 単項演算
299    fn unary(&mut self) -> Result<i64, CompileError> {
300        match self.current_kind() {
301            Some(TokenKind::Plus) => {
302                self.advance();
303                self.unary()
304            }
305            Some(TokenKind::Minus) => {
306                self.advance();
307                Ok(-self.unary()?)
308            }
309            Some(TokenKind::Bang) => {
310                self.advance();
311                let val = self.unary()?;
312                Ok(if val == 0 { 1 } else { 0 })
313            }
314            Some(TokenKind::Tilde) => {
315                self.advance();
316                Ok(!self.unary()?)
317            }
318            _ => self.primary(),
319        }
320    }
321
322    /// 一次式
323    fn primary(&mut self) -> Result<i64, CompileError> {
324        match self.current_kind().cloned() {
325            Some(TokenKind::IntLit(n)) => {
326                self.advance();
327                Ok(n)
328            }
329            Some(TokenKind::UIntLit(n)) => {
330                self.advance();
331                Ok(n as i64)
332            }
333            Some(TokenKind::CharLit(c)) => {
334                self.advance();
335                Ok(c as i64)
336            }
337            Some(TokenKind::WideCharLit(c)) => {
338                self.advance();
339                Ok(c as i64)
340            }
341            Some(TokenKind::LParen) => {
342                self.advance();
343                let val = self.expr()?;
344                if !matches!(self.current_kind(), Some(TokenKind::RParen)) {
345                    return Err(self.error("expected ')'"));
346                }
347                self.advance();
348                Ok(val)
349            }
350            Some(TokenKind::Ident(id)) => {
351                // defined演算子のチェック
352                if Some(id) == self.defined_id {
353                    self.advance();
354                    return self.parse_defined();
355                }
356
357                // 未定義の識別子は0として扱う(C標準)
358                self.advance();
359                Ok(0)
360            }
361            Some(_) => Err(self.error("unexpected token in preprocessor expression")),
362            None => Err(self.error("unexpected end of expression")),
363        }
364    }
365
366    /// defined演算子をパース
367    fn parse_defined(&mut self) -> Result<i64, CompileError> {
368        let has_paren = matches!(self.current_kind(), Some(TokenKind::LParen));
369        if has_paren {
370            self.advance();
371        }
372
373        // 識別子またはキーワードを受け入れる
374        // キーワードも #define で定義される可能性があるため
375        let name = match self.current_kind() {
376            Some(TokenKind::Ident(id)) => Some(*id),
377            Some(kind) if kind.is_keyword() => {
378                // キーワードの名前を取得して検索
379                // インターンされていなければマクロとして定義されていない
380                let kw_name = kind.format(self.interner);
381                self.interner.lookup(&kw_name)
382            }
383            _ => return Err(self.error("expected identifier after 'defined'")),
384        };
385        self.advance();
386
387        if has_paren {
388            if !matches!(self.current_kind(), Some(TokenKind::RParen)) {
389                return Err(self.error("expected ')' after identifier in 'defined'"));
390            }
391            self.advance();
392        }
393
394        // nameがNoneの場合、マクロは定義されていない
395        Ok(match name {
396            Some(n) if self.macros.is_defined(n) => 1,
397            _ => 0,
398        })
399    }
400}
401
402#[cfg(test)]
403mod tests {
404    use super::*;
405    use crate::macro_def::MacroDef;
406    use crate::source::FileId;
407
408    fn make_token(kind: TokenKind) -> Token {
409        Token::new(kind, SourceLocation::default())
410    }
411
412    fn eval_tokens(tokens: &[Token], interner: &StringInterner, macros: &MacroTable) -> i64 {
413        let loc = SourceLocation::new(FileId::default(), 1, 1);
414        let mut eval = PPExprEvaluator::new(tokens, interner, macros, loc);
415        eval.evaluate().unwrap()
416    }
417
418    #[test]
419    fn test_shift_amount_is_masked() {
420        // シフト量 >= 64 で panic せず、TinyCC 同様 63 でマスクする
421        // (perl 5.44 のヘッダに評価時 64 以上になる #if シフト式が存在)
422        let interner = StringInterner::new();
423        let macros = MacroTable::new();
424
425        // 1 << 64 → 1 << 0 = 1
426        let tokens = vec![
427            make_token(TokenKind::IntLit(1)),
428            make_token(TokenKind::LtLt),
429            make_token(TokenKind::IntLit(64)),
430        ];
431        assert_eq!(eval_tokens(&tokens, &interner, &macros), 1);
432
433        // 1 << 65 → 1 << 1 = 2
434        let tokens = vec![
435            make_token(TokenKind::IntLit(1)),
436            make_token(TokenKind::LtLt),
437            make_token(TokenKind::IntLit(65)),
438        ];
439        assert_eq!(eval_tokens(&tokens, &interner, &macros), 2);
440
441        // 256 >> 68 → 256 >> 4 = 16
442        let tokens = vec![
443            make_token(TokenKind::IntLit(256)),
444            make_token(TokenKind::GtGt),
445            make_token(TokenKind::IntLit(68)),
446        ];
447        assert_eq!(eval_tokens(&tokens, &interner, &macros), 16);
448    }
449
450    #[test]
451    fn test_simple_number() {
452        let interner = StringInterner::new();
453        let macros = MacroTable::new();
454        let tokens = vec![make_token(TokenKind::IntLit(42))];
455
456        assert_eq!(eval_tokens(&tokens, &interner, &macros), 42);
457    }
458
459    #[test]
460    fn test_arithmetic() {
461        let interner = StringInterner::new();
462        let macros = MacroTable::new();
463
464        // 2 + 3
465        let tokens = vec![
466            make_token(TokenKind::IntLit(2)),
467            make_token(TokenKind::Plus),
468            make_token(TokenKind::IntLit(3)),
469        ];
470        assert_eq!(eval_tokens(&tokens, &interner, &macros), 5);
471
472        // 10 - 4 * 2
473        let tokens = vec![
474            make_token(TokenKind::IntLit(10)),
475            make_token(TokenKind::Minus),
476            make_token(TokenKind::IntLit(4)),
477            make_token(TokenKind::Star),
478            make_token(TokenKind::IntLit(2)),
479        ];
480        assert_eq!(eval_tokens(&tokens, &interner, &macros), 2);
481    }
482
483    #[test]
484    fn test_comparison() {
485        let interner = StringInterner::new();
486        let macros = MacroTable::new();
487
488        // 5 > 3
489        let tokens = vec![
490            make_token(TokenKind::IntLit(5)),
491            make_token(TokenKind::Gt),
492            make_token(TokenKind::IntLit(3)),
493        ];
494        assert_eq!(eval_tokens(&tokens, &interner, &macros), 1);
495
496        // 2 == 3
497        let tokens = vec![
498            make_token(TokenKind::IntLit(2)),
499            make_token(TokenKind::EqEq),
500            make_token(TokenKind::IntLit(3)),
501        ];
502        assert_eq!(eval_tokens(&tokens, &interner, &macros), 0);
503    }
504
505    #[test]
506    fn test_logical() {
507        let interner = StringInterner::new();
508        let macros = MacroTable::new();
509
510        // 1 && 0
511        let tokens = vec![
512            make_token(TokenKind::IntLit(1)),
513            make_token(TokenKind::AmpAmp),
514            make_token(TokenKind::IntLit(0)),
515        ];
516        assert_eq!(eval_tokens(&tokens, &interner, &macros), 0);
517
518        // 1 || 0
519        let tokens = vec![
520            make_token(TokenKind::IntLit(1)),
521            make_token(TokenKind::PipePipe),
522            make_token(TokenKind::IntLit(0)),
523        ];
524        assert_eq!(eval_tokens(&tokens, &interner, &macros), 1);
525    }
526
527    #[test]
528    fn test_ternary() {
529        let interner = StringInterner::new();
530        let macros = MacroTable::new();
531
532        // 1 ? 10 : 20
533        let tokens = vec![
534            make_token(TokenKind::IntLit(1)),
535            make_token(TokenKind::Question),
536            make_token(TokenKind::IntLit(10)),
537            make_token(TokenKind::Colon),
538            make_token(TokenKind::IntLit(20)),
539        ];
540        assert_eq!(eval_tokens(&tokens, &interner, &macros), 10);
541
542        // 0 ? 10 : 20
543        let tokens = vec![
544            make_token(TokenKind::IntLit(0)),
545            make_token(TokenKind::Question),
546            make_token(TokenKind::IntLit(10)),
547            make_token(TokenKind::Colon),
548            make_token(TokenKind::IntLit(20)),
549        ];
550        assert_eq!(eval_tokens(&tokens, &interner, &macros), 20);
551    }
552
553    #[test]
554    fn test_defined() {
555        let mut interner = StringInterner::new();
556        let mut macros = MacroTable::new();
557
558        let foo = interner.intern("FOO");
559        let defined = interner.intern("defined");
560        let _ = defined; // 登録だけ
561
562        // FOO を定義
563        macros.define(MacroDef::object(foo, vec![], SourceLocation::default()), &interner);
564
565        // defined(FOO)
566        let tokens = vec![
567            make_token(TokenKind::Ident(interner.lookup("defined").unwrap())),
568            make_token(TokenKind::LParen),
569            make_token(TokenKind::Ident(foo)),
570            make_token(TokenKind::RParen),
571        ];
572        assert_eq!(eval_tokens(&tokens, &interner, &macros), 1);
573
574        // defined(BAR) - 未定義
575        let bar = interner.intern("BAR");
576        let tokens = vec![
577            make_token(TokenKind::Ident(interner.lookup("defined").unwrap())),
578            make_token(TokenKind::LParen),
579            make_token(TokenKind::Ident(bar)),
580            make_token(TokenKind::RParen),
581        ];
582        assert_eq!(eval_tokens(&tokens, &interner, &macros), 0);
583    }
584
585    #[test]
586    fn test_unary() {
587        let interner = StringInterner::new();
588        let macros = MacroTable::new();
589
590        // -5
591        let tokens = vec![
592            make_token(TokenKind::Minus),
593            make_token(TokenKind::IntLit(5)),
594        ];
595        assert_eq!(eval_tokens(&tokens, &interner, &macros), -5);
596
597        // !0
598        let tokens = vec![
599            make_token(TokenKind::Bang),
600            make_token(TokenKind::IntLit(0)),
601        ];
602        assert_eq!(eval_tokens(&tokens, &interner, &macros), 1);
603
604        // !1
605        let tokens = vec![
606            make_token(TokenKind::Bang),
607            make_token(TokenKind::IntLit(1)),
608        ];
609        assert_eq!(eval_tokens(&tokens, &interner, &macros), 0);
610    }
611
612    #[test]
613    fn test_parentheses() {
614        let interner = StringInterner::new();
615        let macros = MacroTable::new();
616
617        // (2 + 3) * 4
618        let tokens = vec![
619            make_token(TokenKind::LParen),
620            make_token(TokenKind::IntLit(2)),
621            make_token(TokenKind::Plus),
622            make_token(TokenKind::IntLit(3)),
623            make_token(TokenKind::RParen),
624            make_token(TokenKind::Star),
625            make_token(TokenKind::IntLit(4)),
626        ];
627        assert_eq!(eval_tokens(&tokens, &interner, &macros), 20);
628    }
629}