diff options
Diffstat (limited to 'src/analysis/scan/exprs/call.c')
-rw-r--r-- | src/analysis/scan/exprs/call.c | 223 |
1 files changed, 86 insertions, 137 deletions
diff --git a/src/analysis/scan/exprs/call.c b/src/analysis/scan/exprs/call.c index 76f5fc3..dde627c 100644 --- a/src/analysis/scan/exprs/call.c +++ b/src/analysis/scan/exprs/call.c @@ -24,6 +24,7 @@ #include "call.h" +#include <assert.h> #include <malloc.h> #include <string.h> @@ -48,19 +49,16 @@ static void g_pending_call_dispose(GPendingCall *); /* Procède à la libération totale de la mémoire. */ static void g_pending_call_finalize(GPendingCall *); -/* Définit une base de recherche pour la cible d'appel. */ -static void g_pending_call_set_base(GPendingCall *, GRegisteredItem *); - /* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ /* Reproduit une expression en place dans une nouvelle instance. */ -static GScanExpression *g_pending_call_duplicate(const GPendingCall *); +static void g_pending_call_copy(GPendingCall *, const GPendingCall *); /* Réduit une expression à une forme plus simple. */ -GScanExpression *g_pending_call_reduce(GPendingCall *, GScanContext *, bool); +static bool g_pending_call_reduce(GPendingCall *, GScanContext *, GScanScope *, GScanExpression **); @@ -70,7 +68,7 @@ GScanExpression *g_pending_call_reduce(GPendingCall *, GScanContext *, bool); /* Indique le type défini pour un appel de fonction enregistrée. */ -G_DEFINE_TYPE(GPendingCall, g_pending_call, G_TYPE_SCAN_EXPRESSION); +G_DEFINE_TYPE(GPendingCall, g_pending_call, G_TYPE_NAMED_ACCESS); /****************************************************************************** @@ -98,7 +96,7 @@ static void g_pending_call_class_init(GPendingCallClass *klass) expr = G_SCAN_EXPRESSION_CLASS(klass); expr->cmp_rich = (compare_expr_rich_fc)NULL; - expr->dup = (dup_expr_fc)g_pending_call_duplicate; + expr->copy = (copy_expr_fc)g_pending_call_copy; expr->reduce = (reduce_expr_fc)g_pending_call_reduce; } @@ -118,14 +116,9 @@ static void g_pending_call_class_init(GPendingCallClass *klass) static void g_pending_call_init(GPendingCall *call) { - call->base = NULL; - call->target = NULL; - call->args = NULL; call->count = 0; - call->next = NULL; - } @@ -145,13 +138,9 @@ static void g_pending_call_dispose(GPendingCall *call) { size_t i; /* Boucle de parcours */ - g_clear_object(&call->base); - for (i = 0; i < call->count; i++) g_clear_object(&call->args[i]); - g_clear_object(&call->next); - G_OBJECT_CLASS(g_pending_call_parent_class)->dispose(G_OBJECT(call)); } @@ -171,9 +160,6 @@ static void g_pending_call_dispose(GPendingCall *call) static void g_pending_call_finalize(GPendingCall *call) { - if (call->target != NULL) - free(call->target); - if (call->args != NULL) free(call->args); @@ -185,7 +171,6 @@ static void g_pending_call_finalize(GPendingCall *call) /****************************************************************************** * * * Paramètres : target = désignation de l'objet d'appel à identifier. * -* len = taille de cette désignation. * * args = éventuelle liste d'arguments à actionner. * * count = quantité de ces arguments. * * * @@ -197,13 +182,13 @@ static void g_pending_call_finalize(GPendingCall *call) * * ******************************************************************************/ -GScanExpression *g_pending_call_new(const char *target, size_t len, GScanExpression **args, size_t count) +GScanExpression *g_pending_call_new(const sized_string_t *target, GScanExpression **args, size_t count) { GScanExpression *result; /* Structure à retourner */ result = g_object_new(G_TYPE_PENDING_CALL, NULL); - if (!g_pending_call_create(G_PENDING_CALL(result), target, len, args, count)) + if (!g_pending_call_create(G_PENDING_CALL(result), target, args, count)) g_clear_object(&result); return result; @@ -215,7 +200,6 @@ GScanExpression *g_pending_call_new(const char *target, size_t len, GScanExpress * * * Paramètres : call = instance à initialiser pleinement. * * target = désignation de l'objet d'appel à identifier. * -* len = taille de cette désignation. * * args = éventuelle liste d'arguments à actionner. * * count = quantité de ces arguments. * * * @@ -227,16 +211,14 @@ GScanExpression *g_pending_call_new(const char *target, size_t len, GScanExpress * * ******************************************************************************/ -bool g_pending_call_create(GPendingCall *call, const char *target, size_t len, GScanExpression **args, size_t count) +bool g_pending_call_create(GPendingCall *call, const sized_string_t *target, GScanExpression **args, size_t count) { bool result; /* Bilan à retourner */ size_t i; /* Boucle de parcours */ - result = g_scan_expression_create(G_SCAN_EXPRESSION(call), EVT_PENDING); + result = g_named_access_create(G_NAMED_ACCESS(call), target); if (!result) goto exit; - call->target = strndup(target, len); - call->args = malloc(count * sizeof(GScanExpression *)); call->count = count; @@ -253,48 +235,6 @@ bool g_pending_call_create(GPendingCall *call, const char *target, size_t len, G } -/****************************************************************************** -* * -* Paramètres : call = expression d'appel à actualiser. * -* base = zone de recherche pour la résolution à venir. * -* * -* Description : Définit une base de recherche pour la cible d'appel. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_pending_call_set_base(GPendingCall *call, GRegisteredItem *base) -{ - call->base = base; - g_object_ref(G_OBJECT(base)); - -} - - -/****************************************************************************** -* * -* Paramètres : call = expression d'appel à compléter. * -* next = expression d'appel suivante dans la chaîne. * -* * -* Description : Complète la chaine d'expressions d'appel. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_pending_call_attach_next(GPendingCall *call, GPendingCall *next) -{ - call->next = next; - g_object_ref(G_OBJECT(next)); - -} - - /* ---------------------------------------------------------------------------------- */ /* IMPLEMENTATION DES FONCTIONS DE CLASSE */ @@ -303,23 +243,31 @@ void g_pending_call_attach_next(GPendingCall *call, GPendingCall *next) /****************************************************************************** * * -* Paramètres : expr = expression à copier. * +* Paramètres : dest = emplacement d'enregistrement à constituer. [OUT] * +* src = expression source à copier. * * * * Description : Reproduit une expression en place dans une nouvelle instance.* * * -* Retour : Nouvelle instance d'expression. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static GScanExpression *g_pending_call_duplicate(const GPendingCall *expr) +static void g_pending_call_copy(GPendingCall *dest, const GPendingCall *src) { - GScanExpression *result; /* Instance copiée à retourner */ + GScanExpressionClass *class; /* Classe parente à solliciter */ + size_t i; /* Boucle de parcours */ - result = g_pending_call_new(expr->target, strlen(expr->target), expr->args, expr->count); + class = G_SCAN_EXPRESSION_CLASS(g_pending_call_parent_class); - return result; + class->copy(G_SCAN_EXPRESSION(dest), G_SCAN_EXPRESSION(src)); + + dest->args = malloc(src->count * sizeof(GScanExpression *)); + dest->count = src->count; + + for (i = 0; i < src->count; i++) + dest->args[i] = g_scan_expression_duplicate(src->args[i]); } @@ -328,99 +276,100 @@ static GScanExpression *g_pending_call_duplicate(const GPendingCall *expr) * * * Paramètres : expr = expression à consulter. * * ctx = contexte de suivi de l'analyse courante. * -* final = indique une ultime conversion dans le cycle en cours.* +* scope = portée courante des variables locales. * +* out = zone d'enregistrement de la réduction opérée. [OUT] * * * * Description : Réduit une expression à une forme plus simple. * * * -* Retour : Réduction correspondante, expression déjà réduite, ou NULL. * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * * * * Remarques : - * * * ******************************************************************************/ -GScanExpression *g_pending_call_reduce(GPendingCall *expr, GScanContext *ctx, bool final) +static bool g_pending_call_reduce(GPendingCall *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out) { - GScanExpression *result; /* Instance à renvoyer */ + bool result; /* Bilan à retourner */ + GNamedAccess *new; /* Eventuel étage suivant */ + GPendingCall *new_call; /* Version en appel */ size_t i; /* Boucle de parcours */ - GScanExpression *new; /* Nouvelle expression obtenue */ - bool last; /* Détection de fin de chaîne */ - GRegisteredItem *base; /* Base de recherche courante */ - GRegisteredItem *rebase; /* Nouvelle base résolue */ + GScanExpression *arg; /* Argument réduit à échanger */ + GObject *final; /* Expression ou élément ? */ GScanExpression *new_next; /* Nouvelle version du suivant */ - for (i = 0; i < expr->count; i++) + result = _g_named_access_reduce(G_NAMED_ACCESS(expr), ctx, scope, out); + + if (result && *out != NULL) { - new = g_scan_expression_reduce(expr->args[i], ctx, final); + assert(G_IS_NAMED_ACCESS(*out)); - if (new != NULL) - { - g_object_unref(G_OBJECT(expr->args[i])); - expr->args[i] = new; - } + new = G_NAMED_ACCESS(*out); + *out = NULL; - } + assert(new->target == NULL); + assert(G_IS_PENDING_CALL(new)); + assert(G_IS_REGISTERED_ITEM(new->resolved)); - last = (expr->next == NULL); + new_call = G_PENDING_CALL(new); - if (!last) - new_next = g_scan_expression_duplicate(G_SCAN_EXPRESSION(expr->next)); - else - new_next = NULL; - - if (expr->target != NULL) - { - if (expr->base != NULL) + for (i = 0; i < new_call->count; i++) { - base = expr->base; - g_object_ref(G_OBJECT(base)); - } - else - base = G_REGISTERED_ITEM(get_rost_root_namespace()); + result = g_scan_expression_reduce(new_call->args[i], ctx, scope, &arg); + if (!result) goto exit; - rebase = g_registered_item_resolve(base, expr->target, ctx, - last ? NULL : expr->args, last ? 0 : expr->count, - last, final); + if (arg != NULL) + { + g_object_unref(G_OBJECT(new_call->args[i])); + new_call->args[i] = arg; + } - g_object_unref(G_OBJECT(base)); - if (rebase == NULL) - { - result = NULL; - goto done; } - if (last) - { - g_pending_call_set_base(expr, rebase); + result = g_registered_item_run_call(new->resolved, + new_call->args, + new_call->count, + ctx, scope, &final); - free(expr->target); - expr->target = NULL; + if (result && final != NULL) + { + /** + * Si le produit de l'appel à la fonction est une expression d'évaluation + * classique, alors ce produit constitue la réduction finale de la chaîne. + * + * Ce cas de figure ne se rencontre normalement qu'en bout de chaîne. + */ + if (!G_IS_REGISTERED_ITEM(final)) + { + assert(new->next == NULL); + *out = G_SCAN_EXPRESSION(final); + } + else + { + assert(new->next != NULL); + + new_next = g_scan_expression_duplicate(G_SCAN_EXPRESSION(new->next)); + assert(G_IS_NAMED_ACCESS(new_next)); + + g_named_access_set_base(G_NAMED_ACCESS(new_next), G_REGISTERED_ITEM(final)); + + result = g_scan_expression_reduce(new_next, ctx, scope, out); + + if (result && *out == NULL) + *out = new_next; + else + g_object_unref(G_OBJECT(new_next)); + + } } - else - g_pending_call_set_base(G_PENDING_CALL(new_next), rebase); - - } - if (last) - result = g_registered_item_reduce(expr->base, ctx, expr->args, expr->count, final); + exit: - else - { - result = g_scan_expression_reduce(new_next, ctx, final); - - if (result == NULL) - { - g_object_ref(G_OBJECT(new_next)); - result = new_next; - } + g_object_unref(G_OBJECT(new)); } - done: - - g_clear_object(&new_next); - return result; } |