Commit b85a8135 authored by Lev Walkin's avatar Lev Walkin
Browse files

automatic dependency tracking

parent e44ea0bd
0.9.19: 2005-Aug-16
0.9.19: 2005-Aug-18
* asn1c's -findirect-choice flag generates less dependent code.
* A proper solution to circular references. No kludge flags
should be necessary anymore to produce reference-free code:
recursive dependencies are resolved automatically.
* Test cases 73 & 92 keep track of various circular references.
0.9.18: 2005-Aug-14
......
#undef NDEBUG
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <assert.h>
#include <Everything.h>
int
main(int ac, char **av) {
Everything_t t;
(void)ac; /* Unused argument */
(void)av; /* Unused argument */
memset(&t, 0, sizeof(t));
/*
* No plans to fill it up: just checking whether it compiles or not.
*/
return 0;
}
......@@ -42,6 +42,9 @@ static int expr_elements_count(arg_t *arg, asn1p_expr_t *expr);
static int emit_member_table(arg_t *arg, asn1p_expr_t *expr);
static int emit_tag2member_map(arg_t *arg, tag2el_t *tag2el, int tag2el_count, const char *opt_modifier);
static int emit_include_dependencies(arg_t *arg);
static asn1p_expr_t *terminal_structable(arg_t *arg, asn1p_expr_t *expr);
static int expr_defined_recursively(arg_t *arg, asn1p_expr_t *expr);
static int asn1c_recurse(arg_t *arg, asn1p_expr_t *expr, int (*callback)(arg_t *arg, void *key), void *key);
enum tvm_compat {
_TVM_SAME = 0, /* tags and all_tags are same */
......@@ -274,7 +277,7 @@ asn1c_lang_C_type_SEQUENCE(arg_t *arg) {
if(v->expr_type == A1TC_EXTENSIBLE)
if(comp_mode < 3) comp_mode++;
if(comp_mode == 1)
v->marker.flags |= EM_INDIRECT;
v->marker.flags |= EM_OMITABLE;
EMBED(v);
}
......@@ -335,7 +338,7 @@ asn1c_lang_C_type_SEQUENCE_def(arg_t *arg) {
continue;
}
if(comp_mode == 1)
v->marker.flags |= EM_INDIRECT;
v->marker.flags |= EM_OMITABLE;
emit_member_table(arg, v);
elements++;
});
......@@ -435,7 +438,7 @@ asn1c_lang_C_type_SET(arg_t *arg) {
if(comp_mode < 3) comp_mode++;
}
if(comp_mode == 1)
v->marker.flags |= EM_INDIRECT;
v->marker.flags |= EM_OMITABLE;
EMBED(v);
}
......@@ -509,7 +512,7 @@ asn1c_lang_C_type_SET_def(arg_t *arg) {
if(comp_mode < 3) comp_mode++;
} else {
if(comp_mode == 1)
v->marker.flags |= EM_INDIRECT;
v->marker.flags |= EM_OMITABLE;
emit_member_table(arg, v);
elements++;
}
......@@ -552,7 +555,7 @@ asn1c_lang_C_type_SET_def(arg_t *arg) {
OUT(" | ");
}
OUT("(%d << %d)",
v->marker.flags?0:1,
(v->marker.flags & EM_OMITABLE) != EM_OMITABLE,
7 - (el % 8));
if(el && (el % 8) == 0)
delimit = 1;
......@@ -943,7 +946,6 @@ asn1c_lang_C_type_REFERENCE(arg_t *arg) {
tmp = *arg;
tmp.asn = arg->asn;
tmp.mod = extract->module;
tmp.expr = extract;
ret = arg->default_cb(&tmp);
......@@ -975,10 +977,7 @@ asn1c_lang_C_type_SIMPLE_TYPE(arg_t *arg) {
* as it may recursively include the current structure.
*/
if(expr->marker.flags & (EM_INDIRECT | EM_UNRECURSE)) {
asn1p_expr_t *terminal;
terminal = asn1f_find_terminal_type_ex(arg->asn, expr);
if(terminal
&& (terminal->expr_type & ASN_CONSTR_MASK)) {
if(terminal_structable(arg, expr)) {
tnfmt = TNF_RSAFE;
REDIR(OT_FWD_DECLS);
OUT("%s;\n",
......@@ -1462,10 +1461,9 @@ _add_tag2el_member(arg_t *arg, tag2el_t **tag2el, int *count, int el_no, fte_e f
if(arg->expr->expr_type == A1TC_REFERENCE) {
arg_t tmp = *arg;
asn1p_expr_t *expr;
expr = asn1f_lookup_symbol_ex(tmp.asn, tmp.mod, tmp.expr,
expr = asn1f_lookup_symbol_ex(tmp.asn, tmp.expr,
arg->expr->reference);
if(expr) {
tmp.mod = expr->module;
tmp.expr = expr;
return _add_tag2el_member(&tmp, tag2el, count, el_no, flags);
} else {
......@@ -1612,106 +1610,6 @@ expr_elements_count(arg_t *arg, asn1p_expr_t *expr) {
return elements;
}
static int
emit_include_dependencies(arg_t *arg) {
asn1p_expr_t *expr = arg->expr;
asn1p_expr_t *memb;
TQ_FOR(memb, &(expr->members), next) {
/* Avoid recursive definitions. */
expr_break_recursion(arg, memb);
if(memb->marker.flags & (EM_INDIRECT | EM_UNRECURSE)) {
asn1p_expr_t *terminal;
terminal = asn1f_find_terminal_type_ex(arg->asn, memb);
if(terminal
&& !terminal->parent_expr
&& (terminal->expr_type & ASN_CONSTR_MASK)) {
int saved_target = arg->target->target;
REDIR(OT_FWD_DECLS);
OUT("%s;\n",
asn1c_type_name(arg, memb, TNF_RSAFE));
REDIR(saved_target);
}
}
if((!(memb->expr_type & ASN_CONSTR_MASK)
&& memb->expr_type > ASN_CONSTR_MASK)
|| memb->meta_type == AMT_TYPEREF) {
if(memb->marker.flags & EM_UNRECURSE) {
GEN_POSTINCLUDE(asn1c_type_name(arg,
memb, TNF_INCLUDE));
} else {
GEN_INCLUDE(asn1c_type_name(arg,
memb, TNF_INCLUDE));
}
}
}
return 0;
}
/*
* Check if it is better to make this type indirectly accessed via
* a pointer.
* This may be the case for the following recursive definition:
* Type ::= CHOICE { member Type };
*/
static int
expr_break_recursion(arg_t *arg, asn1p_expr_t *expr) {
asn1p_expr_t *top_parent;
asn1p_expr_t *terminal;
if(expr->marker.flags & EM_UNRECURSE)
return 1; /* Already broken */
terminal = asn1f_find_terminal_type_ex(arg->asn, expr);
/* -findirect-choice compiles members of CHOICE as indirect pointers */
if((arg->flags & A1C_INDIRECT_CHOICE)
&& arg->expr->expr_type == ASN_CONSTR_CHOICE
&& terminal
&& (terminal->expr_type & ASN_CONSTR_MASK)
) {
/* Break cross-reference */
expr->marker.flags |= EM_INDIRECT | EM_UNRECURSE;
return 1;
}
if((expr->marker.flags & EM_INDIRECT)
|| arg->expr->expr_type == ASN_CONSTR_SET_OF
|| arg->expr->expr_type == ASN_CONSTR_SEQUENCE_OF) {
if(terminal
&& !terminal->parent_expr
&& (terminal->expr_type & ASN_CONSTR_MASK)) {
expr->marker.flags |= EM_UNRECURSE;
if(arg->expr->expr_type == ASN_CONSTR_SET_OF
|| arg->expr->expr_type == ASN_CONSTR_SEQUENCE_OF) {
/* Don't put EM_INDIRECT even if recursion */
return 1;
}
/* Fall through */
}
}
/* Look for recursive back-references */
top_parent = expr->parent_expr;
if(top_parent) {
while(top_parent->parent_expr)
top_parent = top_parent->parent_expr;
if(top_parent == terminal) {
/* Explicitly break the recursion */
expr->marker.flags |= EM_INDIRECT | EM_UNRECURSE;
return 1;
}
}
return 0;
}
static int
emit_member_table(arg_t *arg, asn1p_expr_t *expr) {
int save_target;
......@@ -1734,10 +1632,11 @@ emit_member_table(arg_t *arg, asn1p_expr_t *expr) {
OUT("ATF_OPEN_TYPE | ");
OUT("%s, ",
(expr->marker.flags & EM_INDIRECT)?"ATF_POINTER":"ATF_NOFLAGS");
if((expr->marker.flags & EM_OPTIONAL) == EM_OPTIONAL) {
if((expr->marker.flags & EM_OMITABLE) == EM_OMITABLE) {
asn1p_expr_t *tv;
int opts = 0;
for(tv = expr; tv && tv->marker.flags;
for(tv = expr;
tv && (tv->marker.flags & EM_OMITABLE) == EM_OMITABLE;
tv = TQ_NEXT(tv, next), opts++) {
if(tv->expr_type == A1TC_EXTENSIBLE)
opts--;
......@@ -2018,3 +1917,178 @@ out_name_chain(arg_t *arg, enum onc_flags onc_flags) {
return 0;
}
static int
emit_include_dependencies(arg_t *arg) {
asn1p_expr_t *expr = arg->expr;
asn1p_expr_t *memb;
/* Avoid recursive definitions. */
TQ_FOR(memb, &(expr->members), next) {
expr_break_recursion(arg, memb);
}
TQ_FOR(memb, &(expr->members), next) {
if(memb->marker.flags & (EM_INDIRECT | EM_UNRECURSE)) {
if(terminal_structable(arg, memb)) {
int saved_target = arg->target->target;
REDIR(OT_FWD_DECLS);
OUT("%s;\n",
asn1c_type_name(arg, memb, TNF_RSAFE));
REDIR(saved_target);
}
}
if((!(memb->expr_type & ASN_CONSTR_MASK)
&& memb->expr_type > ASN_CONSTR_MASK)
|| memb->meta_type == AMT_TYPEREF) {
if(memb->marker.flags & EM_UNRECURSE) {
GEN_POSTINCLUDE(asn1c_type_name(arg,
memb, TNF_INCLUDE));
} else {
GEN_INCLUDE(asn1c_type_name(arg,
memb, TNF_INCLUDE));
}
}
}
return 0;
}
/*
* Check if it is better to make this type indirectly accessed via
* a pointer.
* This may be the case for the following recursive definition:
* Type ::= CHOICE { member Type };
*/
static int
expr_break_recursion(arg_t *arg, asn1p_expr_t *expr) {
asn1p_expr_t *terminal;
int ret;
if(expr->marker.flags & EM_UNRECURSE)
return 1; /* Already broken */
terminal = asn1f_find_terminal_type_ex(arg->asn, expr);
/* -findirect-choice compiles members of CHOICE as indirect pointers */
if((arg->flags & A1C_INDIRECT_CHOICE)
&& arg->expr->expr_type == ASN_CONSTR_CHOICE
&& terminal
&& (terminal->expr_type & ASN_CONSTR_MASK)
) {
/* Break cross-reference */
expr->marker.flags |= EM_INDIRECT | EM_UNRECURSE;
return 1;
}
if((expr->marker.flags & EM_INDIRECT)
|| arg->expr->expr_type == ASN_CONSTR_SET_OF
|| arg->expr->expr_type == ASN_CONSTR_SEQUENCE_OF) {
if(terminal_structable(arg, expr)) {
expr->marker.flags |= EM_UNRECURSE;
if(arg->expr->expr_type == ASN_CONSTR_SET_OF
|| arg->expr->expr_type == ASN_CONSTR_SEQUENCE_OF) {
/* Don't put EM_INDIRECT even if recursion */
return 1;
}
/* Fall through */
}
}
/* Look for recursive back-references */
ret = expr_defined_recursively(arg, expr);
switch(ret) {
case 2: /* Explicitly break the recursion */
case 1: /* Use safer typing */
expr->marker.flags |= EM_INDIRECT;
expr->marker.flags |= EM_UNRECURSE;
break;
}
return 0;
}
/*
* Check if the type can be represented using simple `struct TYPE`.
*/
static asn1p_expr_t *
terminal_structable(arg_t *arg, asn1p_expr_t *expr) {
asn1p_expr_t *terminal = asn1f_find_terminal_type_ex(arg->asn, expr);
if(terminal
&& !terminal->parent_expr
&& (terminal->expr_type & ASN_CONSTR_MASK)) {
return terminal;
}
return 0;
}
static int
asn1c_recurse(arg_t *arg, asn1p_expr_t *expr, int (*callback)(arg_t *arg, void *key), void *key) {
arg_t tmp = *arg;
int maxret = 0;
int ret;
if(expr->_mark) return 0;
expr->_mark |= TM_RECURSION;
/* Invoke callback for every type going into recursion */
tmp.expr = expr;
maxret = callback(&tmp, key);
if(maxret <= 1) {
/*
* Recursively invoke myself and the callbacks.
*/
TQ_FOR(tmp.expr, &(expr->members), next) {
ret = asn1c_recurse(&tmp, tmp.expr, callback, key);
if(ret > maxret)
maxret = ret;
if(maxret > 1) break;
}
}
expr->_mark &= ~TM_RECURSION;
return maxret;
}
static int
check_is_refer_to(arg_t *arg, void *key) {
asn1p_expr_t *terminal = terminal_structable(arg, arg->expr);
if(terminal == key) {
if(arg->expr->marker.flags & EM_INDIRECT)
return 1; /* This is almost safe indirection */
return 2;
} else if(terminal) {
/* This might be N-step circular loop. Dive into it. */
return asn1c_recurse(arg, terminal, check_is_refer_to, key);
}
return 0;
}
/*
* Check if the possibly inner expression defined recursively.
*/
static int
expr_defined_recursively(arg_t *arg, asn1p_expr_t *expr) {
asn1p_expr_t *terminal;
asn1p_expr_t *topmost;
/* If expression is top-level, there's no way it can be recursive. */
if(expr->parent_expr == 0) return 0;
if(expr->expr_type != A1TC_REFERENCE)
return 0; /* Basic types are never recursive */
terminal = terminal_structable(arg, expr);
if(!terminal) return 0; /* Terminal cannot be indirected */
/* Search for the parent container for the given expression */
topmost = expr;
while(topmost->parent_expr)
topmost = topmost->parent_expr;
/* Look inside the terminal type if it mentions the parent expression */
return asn1c_recurse(arg, terminal, check_is_refer_to, topmost);
}
......@@ -609,13 +609,13 @@ emit_value_determination_code(arg_t *arg, asn1p_expr_type_e etype, asn1cnst_rang
default:
WARNING("%s:%d: Value cannot be determined "
"for constraint check for %s",
arg->mod->source_file_name,
arg->expr->module->source_file_name,
arg->expr->_lineno,
arg->expr->Identifier
);
OUT_NOINDENT(
"#error %s:%d: Value of %s cannot be determined\n",
arg->mod->source_file_name,
arg->expr->module->source_file_name,
arg->expr->_lineno,
arg->expr->Identifier
);
......
......@@ -51,7 +51,7 @@ typedef struct arg_s {
struct compiler_streams *target;
asn1p_t *asn;
asn1p_module_t *mod;
//asn1p_module_t *mod;
asn1p_expr_t *expr;
int embed;
......
......@@ -142,11 +142,10 @@ asn1c_type_name(arg_t *arg, asn1p_expr_t *expr, enum tnfmt _format) {
* This is a reference to a type defined in a class.
* Resolve it and use instead.
*/
tmp.expr = asn1f_class_access_ex(arg->asn, arg->mod,
arg->expr, expr->reference);
tmp.expr = asn1f_class_access_ex(arg->asn,
arg->expr->module, arg->expr, expr->reference);
if(tmp.expr) return NULL;
tmp.mod = tmp.expr->module;
return asn1c_type_name(&tmp, tmp.expr, _format);
}
......
......@@ -17,6 +17,7 @@ asn1c_save_compiled_output(arg_t *arg, const char *datadir,
int argc, char **argv) {
asn1c_fdeps_t *deps = 0;
asn1c_fdeps_t *dlist;
asn1p_module_t *mod;
FILE *mkf;
int i;
......@@ -26,8 +27,8 @@ asn1c_save_compiled_output(arg_t *arg, const char *datadir,
"from %s\n", datadir);
}
TQ_FOR(arg->mod, &(arg->asn->modules), mod_next) {
TQ_FOR(arg->expr, &(arg->mod->members), next) {
TQ_FOR(mod, &(arg->asn->modules), mod_next) {
TQ_FOR(arg->expr, &(mod->members), next) {
if(asn1_lang_map[arg->expr->meta_type]
[arg->expr->expr_type].type_cb) {
if(asn1c_dump_streams(arg, deps))
......@@ -51,8 +52,8 @@ asn1c_save_compiled_output(arg_t *arg, const char *datadir,
}
fprintf(mkf, "ASN_MODULE_SOURCES=");
TQ_FOR(arg->mod, &(arg->asn->modules), mod_next) {
TQ_FOR(arg->expr, &(arg->mod->members), next) {
TQ_FOR(mod, &(arg->asn->modules), mod_next) {
TQ_FOR(arg->expr, &(mod->members), next) {
if(asn1_lang_map[arg->expr->meta_type]
[arg->expr->expr_type].type_cb) {
fprintf(mkf, "\t\\\n\t%s.c",
......@@ -61,8 +62,8 @@ asn1c_save_compiled_output(arg_t *arg, const char *datadir,
}
}
fprintf(mkf, "\n\nASN_MODULE_HEADERS=");
TQ_FOR(arg->mod, &(arg->asn->modules), mod_next) {
TQ_FOR(arg->expr, &(arg->mod->members), next) {
TQ_FOR(mod, &(arg->asn->modules), mod_next) {
TQ_FOR(arg->expr, &(mod->members), next) {
if(asn1_lang_map[arg->expr->meta_type]
[arg->expr->expr_type].type_cb) {
fprintf(mkf, "\t\\\n\t%s.h",
......@@ -208,8 +209,8 @@ asn1c_save_streams(arg_t *arg, asn1c_fdeps_t *deps) {
" * From ASN.1 module \"%s\"\n"
" * \tfound in \"%s\"\n"
" */\n\n",
arg->mod->ModuleName,
arg->mod->source_file_name
expr->module->ModuleName,
expr->module->source_file_name
);
fprintf(fp_h,
"/*\n"
......@@ -217,8 +218,8 @@ asn1c_save_streams(arg_t *arg, asn1c_fdeps_t *deps) {
" * From ASN.1 module \"%s\"\n"
" * \tfound in \"%s\"\n"
" */\n\n",
arg->mod->ModuleName,
arg->mod->source_file_name
expr->module->ModuleName,
expr->module->source_file_name
);
header_id = asn1c_make_identifier(0, expr->Identifier, NULL);
......
......@@ -12,6 +12,7 @@ asn1_compile(asn1p_t *asn, const char *datadir, enum asn1c_flags flags,
int argc, char **argv) {
arg_t arg_s;
arg_t *arg = &arg_s;
asn1p_module_t *mod;
int ret;
/*
......@@ -29,8 +30,8 @@ asn1_compile(asn1p_t *asn, const char *datadir, enum asn1c_flags flags,
/*
* Compile each individual top level structure.
*/
TQ_FOR(arg->mod, &(asn->modules), mod_next) {
TQ_FOR(arg->expr, &(arg->mod->members), next) {
TQ_FOR(mod, &(asn->modules), mod_next) {
TQ_FOR(arg->expr, &(mod->members), next) {
compiler_streams_t *cs = NULL;
if(asn1c_attach_streams(arg->expr))
......
......@@ -7,7 +7,6 @@ extern arg_t a1f_replace_me_with_proper_interface_arg;
asn1p_expr_t *
asn1f_lookup_symbol_ex(
asn1p_t *asn,
asn1p_module_t *mod,
asn1p_expr_t *expr,
asn1p_ref_t *ref) {
arg_t arg;
......@@ -15,13 +14,13 @@ asn1f_lookup_symbol_ex(
memset(&arg, 0, sizeof(arg));
arg.asn = asn;
arg.mod = mod;
arg.mod = expr->module;
arg.expr = expr;
arg.eh = a1f_replace_me_with_proper_interface_arg.eh;
arg.debug = a1f_replace_me_with_proper_interface_arg.debug;
return asn1f_lookup_symbol(&arg, mod, ref);
return asn1f_lookup_symbol(&arg, expr->module, ref);
}
asn1p_expr_t *
......
......@@ -18,7 +18,6 @@ char const *asn1f_printable_value(asn1p_value_t *value);
*/
asn1p_expr_t *asn1f_lookup_symbol_ex(
asn1p_t *asn,
asn1p_module_t *mod,
asn1p_expr_t *expr,
asn1p_ref_t *ref);
......
......@@ -174,11 +174,12 @@ typedef struct asn1p_expr_s {
struct asn1p_expr_marker_s {
enum asn1p_expr_marker_e {
EM_NOMARK,
EM_INDIRECT = 0x01, /* 0001: Represent as pointer */
EM_OPTIONAL = 0x03, /* 0011: Optional member */
EM_DEFAULT = 0x07, /* 0111: default_value */
EM_UNRECURSE = 0x08, /* 1000: Use safe naming */
EM_NOMARK,
EM_INDIRECT = 0x01, /* 00001 Represent as pointer */
EM_OMITABLE = 0x03, /* 00011 May be absent in encoding */
EM_OPTIONAL = 0x07, /* 00111 Optional member */
EM_DEFAULT = 0x0F, /* 01111 default_value */
EM_UNRECURSE = 0x10, /* 10000 Use safe naming */
} flags;
asn1p_value_t *default_value; /* For EM_DEFAULT case */
} marker;
......
......@@ -58,7 +58,7 @@ static asn_TYPE_member_t asn_MBR_T_1[] = {
.memb_constraints = 0, /* Defer constraints checking to the member type */
.name = "s"
},
{ ATF_POINTER, 0, offsetof(struct T, b),
{ ATF_POINTER, 1, offsetof(struct T, b),
.tag = (ASN_TAG_CLASS_CONTEXT | (2 << 2)),
.tag_mode = -1, /* IMPLICIT tag at current level */
.type = (void *)&asn_DEF_BOOLEAN,
......
......@@ -423,7 +423,7 @@ static asn_TYPE_member_t asn_MBR_Stuff_1[] = {
.memb_constraints = 0, /* Defer constraints checking to the member type */
.name = "anything"
},
{ ATF_POINTER, 0, offsetof(struct Stuff, other),
{ ATF_POINTER, 1, offsetof(struct Stuff, other),
.tag = -1 /* Ambiguous tag (CHOICE?) */,