summaryrefslogtreecommitdiff
path: root/src/mcpp-expression.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mcpp-expression.c')
-rw-r--r--src/mcpp-expression.c178
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 );
+}