src/ast/references.c
Non-local references
Returns a list of non-local references.
#include <stdlib.h>
#include <string.h>
#include "ast.h"
#include "symbols.h"
typedef struct {
Ast * scope;
Stack * nonlocals;
int n, dimension;
} Accelerator;
static
bool is_local_declaration (Ast * n, Stack * stack, Ast * scope)
{
if (!strcmp (ast_terminal (n)->start, "point"))
return true;
Ast ** d;
for (int i = 0; (d = stack_index (stack, i)); i++)
if (*d == n)
return true;
else if (*d == scope)
return false;
return false;
}
static
void non_local_references (Ast * n, Stack * stack, void * data);
static
void add_non_local_reference (const char * name, Stack * stack, Accelerator * a)
{
Ast * ref = ast_identifier_declaration (stack, name);
if (!ref) {
#if 0
fprintf (stderr, "%s:%d: warning: '%s' undeclared\n", ast_terminal (n)->file, ast_terminal (n)->line,
ast_terminal (n)->start);
#endif
return; // assumes this is OK i.e. this corresponds mostly with macros and undeclared library functions
}
if (!strcmp (ast_terminal (ref)->file, "ast/defaults.h")) // ignore "internal" variables and macros
return;
if (!is_local_declaration (ref, stack, a->scope) &&
!fast_stack_find (a->nonlocals, ast_terminal (ref)->start)) {
stack_push (a->nonlocals, &ref);
Function call
Ast * definition = ast_parent (ref, sym_function_definition);
if (definition && (ref = ast_find (definition, sym_direct_declarator,
0, sym_direct_declarator,
0, sym_generic_identifier,
0, sym_IDENTIFIER)) &&
!strcmp (ast_terminal (ref)->start, name)) {
Accelerator b = *a;
b.scope = definition;
stack_push (stack, &definition);
ast_traverse (definition, stack, non_local_references, &b);
ast_pop_scope (stack, definition);
}
}
}
static
void non_local_references (Ast * n, Stack * stack, void * data)
{
if (n->sym == sym_IDENTIFIER &&
n->parent->sym == sym_primary_expression) // do not consider structure members
add_non_local_reference (ast_terminal (n)->start, stack, data);
}
void ast_non_local_references (Ast * scope, Ast * argument)
{
AstRoot * root = ast_get_root (scope);
Stack * stack = root->stack;
stack_push (stack, &scope);
Accelerator a = { scope };
a.nonlocals = stack_new (sizeof (Ast *));
add_non_local_reference ("X0", stack, &a);
add_non_local_reference ("Y0", stack, &a);
add_non_local_reference ("Z0", stack, &a);
add_non_local_reference ("L0", stack, &a);
add_non_local_reference ("N", stack, &a);
ast_traverse (scope, stack, non_local_references, &a);
ast_pop_scope (stack, scope);
ast_after (argument, "{");
Ast ** n;
while ((n = stack_pop (a.nonlocals))) {
AstDimensions dim = {0};
Ast * type = ast_identifier_type (*n, &dim, stack), * def;
if (type == (Ast *) &ast_function)
continue; // fixme: external functions not handled yet
const char * start = ast_terminal (*n)->start;
if (!strcmp (start, "NULL"))
continue;
ast_after (argument, "{\"", start, "\""); // name
Type
if (ast_schema (ast_ancestor (type, 5), sym_declaration,
0, sym_declaration_specifiers,
0, sym_storage_class_specifier,
0, sym_TYPEDEF) &&
(def = ast_schema (ast_ancestor (type, 5), sym_declaration,
1, sym_init_declarator_list,
0, sym_init_declarator,
0, sym_declarator,
0, sym_direct_declarator,
0, sym_generic_identifier,
0, sym_IDENTIFIER)))
// typedef
ast_after (argument, ",\"", ast_terminal (def)->start, "\"");
else switch (type->sym) {
case sym_INT: case sym_DOUBLE: case sym_FLOAT:
ast_after (argument, ",\"", ast_terminal (type)->start, "\""); break;
default:
ast_after (argument, ",\"not implemented yet\""); break;
}
Pointer
ast_after (argument, ",(void *)", dim.pointer || dim.dimension ? "" : "&", start);
Array dimensions
if (dim.dimension) {
ast_after (argument, ",(int[]){");
for (Ast ** d = dim.dimension; *d; d++)
ast_right_terminal (argument)->after = ast_str_append (*d, ast_right_terminal (argument)->after);
ast_after (argument, ",0}");
}
else
ast_after (argument, ",NULL");
free (dim.dimension);
Number of pointer dereferences
char s[10];
snprintf (s, 10, "%d", dim.pointer);
ast_after (argument, ",", s);
Reduction
Ast * parameters = ast_child (scope, sym_foreach_parameters);
if (parameters)
foreach_item (parameters, 2, item) {
if (item->child[0]->sym == sym_reduction_list) {
Ast * reductions = item->child[0];
foreach_item (reductions, 1, reduction) {
Ast * identifier = ast_schema (reduction, sym_reduction,
4, sym_reduction_array,
0, sym_generic_identifier,
0, sym_IDENTIFIER);
if (!strcmp (ast_terminal (identifier)->start, start)) {
char * operator = ast_left_terminal (reduction->child[2])->start;
Ast * array = ast_schema (reduction, sym_reduction,
4, sym_reduction_array,
3, sym_expression);
if (array) {
// fixme: not implemented yet
}
else
ast_after (argument, ",",
!strcmp(operator, "min") ? "'m'" :
!strcmp(operator, "max") ? "'M'" :
!strcmp(operator, "+") ? "'+'" :
"'?'");
}
}
}
}
ast_after (argument, "},");
}
ast_after (argument, "{0}}");
stack_destroy (a.nonlocals);
}