diff options
Diffstat (limited to 'src/mcpp-expression.c')
| -rw-r--r-- | src/mcpp-expression.c | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/src/mcpp-expression.c b/src/mcpp-expression.c new file mode 100644 index 0000000..1f9532d --- /dev/null +++ b/src/mcpp-expression.c @@ -0,0 +1,178 @@ +#include <defs.h> +#include <mcpp-expr.h> + +/* + * 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 ); +} |
