#include #include /* * The front end keeps the already established mcpu-cpp preprocessing order: * handle the special defined operator first, expand macros second, then pass * the resulting UCS-2 expression to the ZUBR parser generated from * mcpp-expr.zubr. */ static int expr_identifier_start( __mpu_char16_t c ) { return( mcpu_pp_is_identifier_start(c) ); } static int expr_identifier_char( __mpu_char16_t c ) { return( mcpu_pp_is_identifier_char(c) ); } static int expr_space( __mpu_char16_t c ) { return( c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\f' || c == '\v' ); } static int append_defined_value( mcpu_macro_table *macros, const __mpu_char16_t *text, size_t length, size_t *pos, mcpu_text *output, const char *filename, unsigned line_number ) { size_t p = *pos; size_t start; size_t end; int parenthesized = 0; while( p < length && expr_space(text[p]) ) ++p; if( p < length && text[p] == '(' ) { parenthesized = 1; ++p; while( p < length && expr_space(text[p]) ) ++p; } if( p >= length || !expr_identifier_start(text[p]) ) { fprintf( stderr, "%s:%u: error: identifier expected after defined\n", filename, line_number ); return( -1 ); } start = p++; while( p < length && expr_identifier_char(text[p]) ) ++p; end = p; while( p < length && expr_space(text[p]) ) ++p; if( parenthesized ) { if( p >= length || text[p] != ')' ) { fprintf( stderr, "%s:%u: error: missing ')' after defined\n", filename, line_number ); return( -1 ); } ++p; } if( mcpu_text_append_ascii( output, mcpu_macro_find(macros, text + start, end - start) ? "1" : "0") != 0 ) return( -1 ); *pos = p; return( 0 ); } static int replace_defined_operators( mcpu_macro_table *macros, const __mpu_char16_t *text, size_t length, mcpu_text *output, const char *filename, unsigned line_number ) { size_t p = 0; __mpu_char16_t quote = 0; int escaped = 0; mcpu_text_free( output ); mcpu_text_init( output ); while( p < length ) { __mpu_char16_t c = text[p]; if( quote ) { if( mcpu_text_append_char(output, c) != 0 ) return( -1 ); if( escaped ) escaped = 0; else if( c == '\\' ) escaped = 1; else if( c == quote ) quote = 0; ++p; continue; } if( c == '\'' || c == '"' ) { quote = c; if( mcpu_text_append_char(output, c) != 0 ) return( -1 ); ++p; continue; } if( expr_identifier_start(c) ) { size_t start = p++; while( p < length && expr_identifier_char(text[p]) ) ++p; if( p - start == 7 && mcpu_text_equal_ascii(text + start, p - start, "defined") ) { if( append_defined_value(macros, text, length, &p, output, filename, line_number) != 0 ) return( -1 ); } else if( mcpu_text_append(output, text + start, p - start) != 0 ) return( -1 ); continue; } if( mcpu_text_append_char(output, c) != 0 ) return( -1 ); ++p; } return( 0 ); } int mcpp_eval_if_expression( mcpu_macro_table *macros, const __mpu_char16_t *text, size_t length, enum mcpu_language language, const mcpu_macro_expansion_context *context, const char *filename, unsigned line_number, int *result ) { mcpu_text defined; mcpu_text expanded; int rc = -1; if( macros == NULL || text == NULL || context == NULL || filename == NULL || result == NULL ) { errno = EINVAL; return( -1 ); } mcpu_text_init( &defined ); mcpu_text_init( &expanded ); if( replace_defined_operators(macros, text, length, &defined, filename, line_number) != 0 || mcpu_macro_expand(macros, defined.data, defined.length, language, context, &expanded) != 0 ) goto done; rc = mcpp_expr_parse( expanded.data, expanded.length, filename, line_number, context->options, result ); done: mcpu_text_free( &defined ); mcpu_text_free( &expanded ); return( rc ); }