// (C) Copyright 2016 Jethro G. Beekman // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Evaluating C expressions from tokens. //! //! Numerical operators are supported. All numerical values are treated as //! `i64` or `f64`. Type casting is not supported. `i64` are converted to //! `f64` when used in conjunction with a `f64`. Right shifts are always //! arithmetic shifts. //! //! The `sizeof` operator is not supported. //! //! String concatenation is supported, but width prefixes are ignored; all //! strings are treated as narrow strings. //! //! Use the `IdentifierParser` to substitute identifiers found in expressions.
use std::collections::HashMap; use std::num::Wrapping; use std::ops::{
AddAssign, BitAndAssign, BitOrAssign, BitXorAssign, DivAssign, MulAssign, RemAssign, ShlAssign,
ShrAssign, SubAssign,
};
usecrate::literal::{self, CChar}; usecrate::token::{Kind as TokenKind, Token}; usecrate::ToCexprResult; use nom::branch::alt; use nom::combinator::{complete, map, map_opt}; use nom::multi::{fold_many0, many0, separated_list0}; use nom::sequence::{delimited, pair, preceded}; use nom::*;
/// A shorthand for the type of cexpr expression evaluation results. pubtype CResult<'a, R> = IResult<&'a [Token], R, crate::Error<&'a [Token]>>;
/// The result of parsing a literal or evaluating an expression. #[derive(Debug, Clone, PartialEq)] #[allow(missing_docs)] pubenum EvalResult {
Int(Wrapping<i64>),
Float(f64),
Char(CChar),
Str(Vec<u8>),
Invalid,
}
/// Create a new `IdentifierParser` with a set of known identifiers. When /// a known identifier is encountered during parsing, it is substituted /// for the value specified. pubfn new(identifiers: &HashMap<Vec<u8>, EvalResult>) -> IdentifierParser<'_> {
IdentifierParser { identifiers }
}
/// Parse and evaluate an expression of a list of tokens. /// /// Returns an error if the input is not a valid expression or if the token /// stream contains comments, keywords or unknown identifiers. pubfn expr<'a>(&self, input: &'a [Token]) -> CResult<'a, EvalResult> { self.as_ref().expr(input)
}
/// Parse and evaluate a macro definition from a list of tokens. /// /// Returns the identifier for the macro and its replacement evaluated as an /// expression. The input should not include `#define`. /// /// Returns an error if the replacement is not a valid expression, if called /// on most function-like macros, or if the token stream contains comments, /// keywords or unknown identifiers. /// /// N.B. This is intended to fail on function-like macros, but if it the /// macro takes a single argument, the argument name is defined as an /// identifier, and the macro otherwise parses as an expression, it will /// return a result even on function-like macros. /// /// ```c /// // will evaluate into IDENTIFIER /// #define DELETE(IDENTIFIER) /// // will evaluate into IDENTIFIER-3 /// #define NEGATIVE_THREE(IDENTIFIER) -3 /// ``` pubfn macro_definition<'a>(&self, input: &'a [Token]) -> CResult<'a, (&'a [u8], EvalResult)> { crate::assert_full_parse(self.as_ref().macro_definition(input))
}
}
/// Parse and evaluate an expression of a list of tokens. /// /// Returns an error if the input is not a valid expression or if the token /// stream contains comments, keywords or identifiers. pubfn expr(input: &[Token]) -> CResult<'_, EvalResult> {
IdentifierParser::new(&HashMap::new()).expr(input)
}
/// Parse and evaluate a macro definition from a list of tokens. /// /// Returns the identifier for the macro and its replacement evaluated as an /// expression. The input should not include `#define`. /// /// Returns an error if the replacement is not a valid expression, if called /// on a function-like macro, or if the token stream contains comments, /// keywords or identifiers. pubfn macro_definition(input: &[Token]) -> CResult<'_, (&'_ [u8], EvalResult)> {
IdentifierParser::new(&HashMap::new()).macro_definition(input)
}
/// Parse a functional macro declaration from a list of tokens. /// /// Returns the identifier for the macro and the argument list (in order). The /// input should not include `#define`. The actual definition is not parsed and /// may be obtained from the unparsed data returned. /// /// Returns an error if the input is not a functional macro or if the token /// stream contains comments. /// /// # Example /// ``` /// use cexpr::expr::{IdentifierParser, EvalResult, fn_macro_declaration}; /// use cexpr::assert_full_parse; /// use cexpr::token::Kind::*; /// use cexpr::token::Token; /// /// // #define SUFFIX(arg) arg "suffix" /// let tokens = vec![ /// (Identifier, &b"SUFFIX"[..]).into(), /// (Punctuation, &b"("[..]).into(), /// (Identifier, &b"arg"[..]).into(), /// (Punctuation, &b")"[..]).into(), /// (Identifier, &b"arg"[..]).into(), /// (Literal, &br#""suffix""#[..]).into(), /// ]; /// /// // Try to parse the functional part /// let (expr, (ident, args)) = fn_macro_declaration(&tokens).unwrap(); /// assert_eq!(ident, b"SUFFIX"); /// /// // Create dummy arguments /// let idents = args.into_iter().map(|arg| /// (arg.to_owned(), EvalResult::Str(b"test".to_vec())) /// ).collect(); /// /// // Evaluate the macro /// let (_, evaluated) = assert_full_parse(IdentifierParser::new(&idents).expr(expr)).unwrap(); /// assert_eq!(evaluated, EvalResult::Str(b"testsuffix".to_vec())); /// ``` pubfn fn_macro_declaration(input: &[Token]) -> CResult<'_, (&[u8], Vec<&[u8]>)> {
pair(
identifier_token,
delimited(
p("("),
separated_list0(p(","), identifier_token),
p(")"),
),
)(input)
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-06-19)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.