gskslpreprocessor: Implement #ifdef, #else and #endif

This commit is contained in:
Benjamin Otte
2017-10-01 02:03:44 +02:00
parent a05961d57a
commit 7b416c9dc5

View File

@@ -40,8 +40,18 @@ struct _GskSlPreprocessor
GArray *tokens;
GHashTable *defines;
gboolean fatal_error;
GSList *conditionals;
};
typedef enum {
/* ignore this part, the last conditional check didn't match */
GSK_COND_IGNORE = (1 << 0),
/* we're inside the else block, so no more elif */
GSK_COND_ELSE = (1 << 1),
/* we've had a match in one of the previous blocks (or this one matches) */
GSK_COND_MATCH = (1 << 2)
} GskConditional;
/* API */
static void
@@ -104,6 +114,7 @@ gsk_sl_preprocessor_unref (GskSlPreprocessor *preproc)
if (preproc->ref_count > 0)
return;
g_slist_free (preproc->conditionals);
g_hash_table_destroy (preproc->defines);
gsk_sl_tokenizer_unref (preproc->tokenizer);
g_object_unref (preproc->compiler);
@@ -118,6 +129,43 @@ gsk_sl_preprocessor_has_fatal_error (GskSlPreprocessor *preproc)
return preproc->fatal_error;
}
static void
gsk_sl_preprocessor_push_conditional (GskSlPreprocessor *preproc,
GskConditional cond)
{
preproc->conditionals = g_slist_prepend (preproc->conditionals, GUINT_TO_POINTER (cond));
}
static GskConditional
gsk_sl_preprocessor_pop_conditional (GskSlPreprocessor *preproc)
{
GskConditional cond = GPOINTER_TO_UINT (preproc->conditionals->data);
preproc->conditionals = g_slist_remove (preproc->conditionals, preproc->conditionals->data);
return cond;
}
static gboolean
gsk_sl_preprocessor_has_conditional (GskSlPreprocessor *preproc)
{
return preproc->conditionals != NULL;
}
static gboolean
gsk_sl_preprocessor_in_ignored_conditional (GskSlPreprocessor *preproc)
{
GSList *l;
for (l = preproc->conditionals; l; l = l->next)
{
if (GPOINTER_TO_UINT (l->data) & GSK_COND_IGNORE)
return TRUE;
}
return FALSE;
}
static gboolean
gsk_sl_preprocessor_next_token (GskSlPreprocessor *preproc,
GskSlPpToken *pp,
@@ -144,6 +192,12 @@ gsk_sl_preprocessor_append_token (GskSlPreprocessor *preproc,
GskSlPpToken *pp,
GSList *used_defines)
{
if (gsk_sl_preprocessor_in_ignored_conditional (preproc))
{
gsk_sl_preprocessor_clear_token (pp);
return;
}
if (gsk_sl_token_is (&pp->token, GSK_SL_TOKEN_IDENTIFIER))
{
GskSlDefine *define;
@@ -194,7 +248,158 @@ gsk_sl_preprocessor_handle_preprocessor_directive (GskSlPreprocessor *preproc)
if (gsk_sl_token_is (&pp.token, GSK_SL_TOKEN_IDENTIFIER))
{
if (g_str_equal (pp.token.str, "define"))
if (g_str_equal (pp.token.str, "else"))
{
if (gsk_sl_preprocessor_has_conditional (preproc))
{
GskConditional cond = gsk_sl_preprocessor_pop_conditional (preproc);
if (cond & GSK_COND_ELSE)
{
gsk_sl_preprocessor_error_full (preproc, PREPROCESSOR, &pp.location, "#else after #else.");
cond |= GSK_COND_IGNORE;
}
else if (cond & GSK_COND_MATCH)
cond |= GSK_COND_IGNORE;
else
cond &= ~GSK_COND_IGNORE;
cond |= GSK_COND_ELSE | GSK_COND_MATCH;
gsk_sl_preprocessor_push_conditional (preproc, cond);
}
else
{
gsk_sl_preprocessor_error_full (preproc, PREPROCESSOR, &pp.location, "#else without #if.");
}
gsk_sl_preprocessor_clear_token (&pp);
if (!gsk_sl_preprocessor_next_token (preproc, &pp, &was_newline))
{
gsk_sl_preprocessor_error_full (preproc, PREPROCESSOR, &pp.location, "Expected newline after #else.");
gsk_sl_preprocessor_clear_token (&pp);
}
else
{
gsk_sl_preprocessor_handle_token (preproc, &pp, was_newline);
}
return;
}
#if 0
else if (g_str_equal (pp.token.str, "elif"))
{
}
#endif
else if (g_str_equal (pp.token.str, "endif"))
{
if (gsk_sl_preprocessor_has_conditional (preproc))
{
gsk_sl_preprocessor_pop_conditional (preproc);
}
else
{
gsk_sl_preprocessor_error_full (preproc, PREPROCESSOR, &pp.location, "#endif without #if.");
}
gsk_sl_preprocessor_clear_token (&pp);
if (!gsk_sl_preprocessor_next_token (preproc, &pp, &was_newline))
{
gsk_sl_preprocessor_error_full (preproc, PREPROCESSOR, &pp.location, "Expected newline after #endif.");
gsk_sl_preprocessor_clear_token (&pp);
}
else
{
gsk_sl_preprocessor_handle_token (preproc, &pp, was_newline);
}
return;
}
#if 0
else if (g_str_equal (pp.token.str, "if"))
{
}
#endif
else if (g_str_equal (pp.token.str, "ifdef"))
{
gsk_sl_preprocessor_clear_token (&pp);
if (gsk_sl_preprocessor_next_token (preproc, &pp, &was_newline))
{
gsk_sl_preprocessor_error_full (preproc, PREPROCESSOR, &pp.location, "No variable after #ifdef.");
gsk_sl_preprocessor_handle_token (preproc, &pp, was_newline);
return;
}
if (!gsk_sl_token_is (&pp.token, GSK_SL_TOKEN_IDENTIFIER))
{
gsk_sl_preprocessor_error_full (preproc, PREPROCESSOR, &pp.location, "Expected identifier after #ifdef.");
gsk_sl_preprocessor_clear_token (&pp);
}
else
{
if (g_hash_table_lookup (preproc->defines, pp.token.str))
{
gsk_sl_preprocessor_push_conditional (preproc, GSK_COND_MATCH);
}
else
{
gsk_sl_preprocessor_push_conditional (preproc, GSK_COND_IGNORE);
}
if (!gsk_sl_preprocessor_next_token (preproc, &pp, &was_newline))
{
gsk_sl_preprocessor_error_full (preproc, PREPROCESSOR, &pp.location, "Expected newline after #ifdef.");
gsk_sl_preprocessor_clear_token (&pp);
}
else
{
gsk_sl_preprocessor_handle_token (preproc, &pp, was_newline);
}
return;
}
}
else if (g_str_equal (pp.token.str, "ifndef"))
{
gsk_sl_preprocessor_clear_token (&pp);
if (gsk_sl_preprocessor_next_token (preproc, &pp, &was_newline))
{
gsk_sl_preprocessor_error_full (preproc, PREPROCESSOR, &pp.location, "No variable after #ifndef.");
gsk_sl_preprocessor_handle_token (preproc, &pp, was_newline);
return;
}
if (!gsk_sl_token_is (&pp.token, GSK_SL_TOKEN_IDENTIFIER))
{
gsk_sl_preprocessor_error_full (preproc, PREPROCESSOR, &pp.location, "Expected identifier after #ifndef.");
gsk_sl_preprocessor_clear_token (&pp);
}
else
{
if (g_hash_table_lookup (preproc->defines, pp.token.str))
{
gsk_sl_preprocessor_push_conditional (preproc, GSK_COND_IGNORE);
}
else
{
gsk_sl_preprocessor_push_conditional (preproc, GSK_COND_MATCH);
}
if (!gsk_sl_preprocessor_next_token (preproc, &pp, &was_newline))
{
gsk_sl_preprocessor_error_full (preproc, PREPROCESSOR, &pp.location, "Expected newline after #ifndef.");
gsk_sl_preprocessor_clear_token (&pp);
}
else
{
gsk_sl_preprocessor_handle_token (preproc, &pp, was_newline);
}
return;
}
}
else if (gsk_sl_preprocessor_in_ignored_conditional (preproc))
{
/* All checks above are for preprocessor directives that are checked even in
* ignored parts of code */
gsk_sl_preprocessor_clear_token (&pp);
/* Everything below has no effect in ignored parts of the code */
}
else if (g_str_equal (pp.token.str, "define"))
{
gsk_sl_preprocessor_clear_token (&pp);
if (gsk_sl_preprocessor_next_token (preproc, &pp, &was_newline))
@@ -229,13 +434,10 @@ gsk_sl_preprocessor_handle_preprocessor_directive (GskSlPreprocessor *preproc)
}
}
#if 0
else if (g_str_equal (pp.token.str, "else"))
else if (g_str_equal (pp.token.str, "line"))
{
}
else if (g_str_equal (pp.token.str, "elif"))
{
}
else if (g_str_equal (pp.token.str, "endif"))
else if (g_str_equal (pp.token.str, "pragma"))
{
}
else if (g_str_equal (pp.token.str, "error"))
@@ -244,21 +446,6 @@ gsk_sl_preprocessor_handle_preprocessor_directive (GskSlPreprocessor *preproc)
else if (g_str_equal (pp.token.str, "extension"))
{
}
else if (g_str_equal (pp.token.str, "if"))
{
}
else if (g_str_equal (pp.token.str, "ifdef"))
{
}
else if (g_str_equal (pp.token.str, "ifndef"))
{
}
else if (g_str_equal (pp.token.str, "line"))
{
}
else if (g_str_equal (pp.token.str, "pragma"))
{
}
#endif
else if (g_str_equal (pp.token.str, "undef"))
{