src/ast/references.c
External references
Returns a list of external references.
#include <stdlib.h>
#include <string.h>
#include "ast.h"
#include "symbols.h"
typedef struct {
Ast * scope;
Stack * nonlocals, * attributes;
int n, dimension;
} Accelerator;
staticbool 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;
}
staticvoid external_references (Ast * n, Stack * stack, Accelerator * a);
staticvoid add_external_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,
(n)->start);
ast_terminal #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)) {
Function call
Ast * definition = ast_parent (ref, sym_function_definition), * def;
if (definition && (def = ast_find (definition, sym_direct_declarator,
0, sym_direct_declarator,
0, sym_generic_identifier,
0, sym_IDENTIFIER)) &&
!strcmp (ast_terminal (def)->start, name)) {
Accelerator b = *a;
.scope = definition;
b(stack, &definition);
stack_push external_references (definition, stack, &b);
(stack, definition);
ast_pop_scope ->nonlocals = b.nonlocals;
a->attributes = b.attributes;
a}
(a->nonlocals, &ref);
stack_push }
}
staticvoid external_references (Ast * n, Stack * stack, Accelerator * a)
{
if (!n || n == ast_placeholder ||
(n->sym == sym_initializer && n->parent->sym == sym_parameter_declaration))
return;
Ast * scope = ast_push_declarations (n, stack);
if (n->child)
for (Ast ** c = n->child; *c; c++)
external_references (*c, stack, a);
if (ast_schema (n->parent, sym_primary_expression,
0, sym_IDENTIFIER) &&
(ast_terminal (n)->start, "_attribute"))
strcmp add_external_reference (ast_terminal (n)->start, stack, a);
else if ((n->sym == sym_IDENTIFIER && ast_attribute_access (ast_ancestor (n, 3), stack)) ||
(n = ast_attribute_array_access (ast_ancestor (n, 3)))) {
Scalar attribute
Ast * found = fast_stack_find (a->attributes, ast_terminal (n)->start);
if (!found) {
Ast * attributes = ast_find (ast_ancestor (ast_identifier_declaration (stack, "_Attributes"), 6),
);
sym_struct_declaration_listassert (attributes);
= NULL;
found (attributes, 1, decl) {
foreach_item Ast * list = ast_schema (decl, sym_struct_declaration,
1, sym_struct_declarator_list);
(list, 2, j) {
foreach_item Ast * identifier = ast_find (j, sym_IDENTIFIER);
if (identifier && !strcmp (ast_terminal (identifier)->start, ast_terminal (n)->start)) {
= identifier; break;
found }
}
if (found)
break;
}
if (found)
(a->attributes, &found);
stack_push }
}
(stack, scope);
ast_pop_scope }
staticchar * add_reference (Ast * ref, char * references, Ast * scope, Stack * stack, Stack * functions)
{
const char * start = ast_terminal (ref)->start;
if (!strcmp (start, "NULL"))
return references;
AstDimensions dim = {0};
Ast * type = ast_identifier_type (ref, &dim, stack);
Ast * attributes = ast_parent (ref, sym_struct_or_union_specifier);
if (type == (Ast *) &ast_function) {
if (!strcmp (start, "qassert"))
return references;
Function pointers
if (ast_schema (ast_ancestor (ref, 4), sym_direct_declarator,
1, sym_declarator,
0, sym_pointer)) {
(references, "{.name=\"", attributes ? "." : "", start,
str_append "\",.type=sym_function_declaration");
if (attributes)
(references, ",.nd=attroffset(", start, ")},");
str_append
else(references, ",.pointer=(void *)(long)", start, "},");
str_append }
Function definitions
else if (ast_ancestor (ref, 6)->sym == sym_function_definition) {
(references, "{.name=\"", attributes ? "." : "", start,
str_append "\",.type=sym_function_definition,.pointer=(void *)(long)", start, "},");
if (!fast_stack_find (functions, ast_terminal (ref)->start))
(functions, &ref);
stack_push }
return references;
}
(references, "{.name=\"", attributes ? "." : "", !strcmp (start, "val") ? "_val" : start, "\""); str_append
Type
Ast * def;
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
if (!strcmp (ast_terminal (def)->start, "scalar"))
(references, ",.type=sym_SCALAR");
str_append else if (!strcmp (ast_terminal (def)->start, "vector"))
(references, ",.type=sym_VECTOR");
str_append else if (!strcmp (ast_terminal (def)->start, "tensor"))
(references, ",.type=sym_TENSOR");
str_append else if (!strcmp (ast_terminal (def)->start, "coord"))
(references, ",.type=sym_COORD");
str_append else if (!strcmp (ast_terminal (def)->start, "_coord"))
(references, ",.type=sym__COORD");
str_append else if (!strcmp (ast_terminal (def)->start, "vec4"))
(references, ",.type=sym_VEC4");
str_append else if (!strcmp (ast_terminal (def)->start, "ivec"))
(references, ",.type=sym_IVEC");
str_append else if (!strcmp (ast_terminal (def)->start, "bool"))
(references, ",.type=sym_BOOL");
str_append
else(references, ",.type=sym_TYPEDEF");
str_append }
else if (ref->parent->sym == sym_enumeration_constant)
(references, ",.type=sym_enumeration_constant");
str_append else {
char s[20]; snprintf (s, 19, "%d", type->sym);
(references, ",.type=", s);
str_append }
Is this a global variable?
if (!attributes && !ast_parent (ref, sym_compound_statement) && !ast_parent (ref, sym_parameter_declaration))
(references, ",.global=1"); str_append
Assumes ’double *’ are references to arrays with ‘nl’ elements. Fixme: this is very specific and should be made more general e.g. systematically using ‘fat pointers’ to get array sizes.
Ast * nl;
if (type->sym == sym_DOUBLE && dim.pointer == 1 && !dim.dimension && strcmp (ast_terminal (ref)->start, "_constant") &&
(nl = ast_identifier_declaration (stack, "nl"))) {
.pointer = 0;
dim.dimension = malloc (2*sizeof (Ast *));
dim.dimension[0] = nl;
dim.dimension[1] = NULL;
dim}
Pointer
if (!(attributes || ref->parent->sym == sym_enumeration_constant))
(references, ",.pointer=(void *)", dim.pointer || (dim.dimension && (*dim.dimension)->sym != sym_VOID) ?
str_append "" : "&", start);
Attribute offset or enumeration constant or number of pointer dereferences
if (attributes)
(references, ",.nd=attroffset(", start, ")");
str_append else if (ref->parent->sym == sym_enumeration_constant)
(references, ",.nd=", start);
str_append else if (dim.pointer) {
char s[10];
(s, 10, "%d", dim.pointer);
snprintf (references, ",.nd=", s);
str_append }
Reduction
Ast * parameters = ast_child (scope, sym_argument_expression_list);
if (parameters)
(parameters, 2, item) {
foreach_item Ast * reductions = ast_find (item, sym_reduction_list);
(reductions, 1, reduction) {
foreach_item 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(references, ",.reduct=",
str_append !strcmp(operator, "min") ? "'m'" :
!strcmp(operator, "max") ? "'M'" :
!strcmp(operator, "+") ? "'+'" :
"'?'");
}
}
}
Array dimensions
if (dim.dimension) {
if ((*dim.dimension)->sym != sym_VOID) {
(references, ",.data=(int[]){");
str_append for (Ast ** d = dim.dimension; *d; d++)
= ast_str_append (*d, references);
references (references, ",0}");
str_append }
else if (*(dim.dimension + 1) == NULL) { // a single undefined dimension
Ast * initializer = ast_schema (ast_parent (ref, sym_init_declarator), sym_init_declarator,
2, sym_initializer,
1, sym_initializer_list);
if (initializer) {
int n = 0;
(initializer, 2, item)
foreach_item ++;
nchar s[20];
(s, 19, "%d", n);
snprintf (references, ",.data=(int[]){", s, ",0}");
str_append }
}
}
free (dim.dimension);
(references, "},");
str_append
return references;
}
char * ast_external_references (Ast * scope, char * references, Stack * functions)
{
AstRoot * root = ast_get_root (scope);
Stack * stack = root->stack;
(stack, &scope);
stack_push Accelerator a = { scope };
.nonlocals = stack_new (sizeof (Ast *));
a.attributes = stack_new (sizeof (Ast *));
aexternal_references (scope, stack, &a);
(stack, scope);
ast_pop_scope
Ast ** n;
for (int i = 0; (n = stack_indexi (a.attributes, i)) && (!references || !strstr (references, "@error ")); i++)
= add_reference (*n, references, scope, stack, functions);
references for (int i = 0; (n = stack_indexi (a.nonlocals, i)) && (!references || !strstr (references, "@error ")); i++)
= add_reference (*n, references, scope, stack, functions);
references
(a.nonlocals);
stack_destroy (a.attributes);
stack_destroy
return references;
}