support for a class of circular references
git-svn-id: https://asn1c.svn.sourceforge.net/svnroot/asn1c/trunk@749 59561ff5-6e30-0410-9f3c-9617f08c8826
diff --git a/libasn1compiler/asn1c_C.c b/libasn1compiler/asn1c_C.c
index 41ad21e..b8a7428 100644
--- a/libasn1compiler/asn1c_C.c
+++ b/libasn1compiler/asn1c_C.c
@@ -35,6 +35,7 @@
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 int out_name_chain(arg_t *arg, int check_reserved_keywords);
enum tvm_compat {
@@ -59,16 +60,9 @@
OUT("/* Context for parsing across buffer boundaries */\n"); \
OUT("asn_struct_ctx_t _asn_ctx;\n"));
+
#define DEPENDENCIES do { \
- asn1p_expr_t *__m; \
- TQ_FOR(__m, &(expr->members), next) { \
- if((!(__m->expr_type & ASN_CONSTR_MASK) \
- && __m->expr_type > ASN_CONSTR_MASK) \
- || __m->meta_type == AMT_TYPEREF) { \
- GEN_INCLUDE(asn1c_type_name(arg, \
- __m, TNF_INCLUDE)); \
- } \
- } \
+ emit_include_dependencies(arg); \
if(expr->expr_type == ASN_CONSTR_SET_OF) \
GEN_INCLUDE("asn_SET_OF"); \
if(expr->expr_type == ASN_CONSTR_SEQUENCE_OF) \
@@ -81,7 +75,6 @@
int
asn1c_lang_C_type_REAL(arg_t *arg) {
- REDIR(OT_DEPS);
return asn1c_lang_C_type_SIMPLE_TYPE(arg);
}
@@ -245,7 +238,7 @@
}
PCTX_DEF;
- OUT("} %s%s%s", expr->marker.flags?"*":"",
+ OUT("} %s%s%s", (expr->marker.flags & EM_INDIRECT)?"*":"",
expr->_anonymous_type ? "" : MKID(expr->Identifier),
arg->embed ? "" : "_t");
@@ -406,7 +399,7 @@
);
PCTX_DEF;
- OUT("} %s%s%s", expr->marker.flags?"*":"",
+ OUT("} %s%s%s", (expr->marker.flags & EM_INDIRECT)?"*":"",
expr->_anonymous_type ? "" : MKID(expr->Identifier),
arg->embed ? "" : "_t");
@@ -567,7 +560,7 @@
int
asn1c_lang_C_type_SEx_OF(arg_t *arg) {
asn1p_expr_t *expr = arg->expr;
- asn1p_expr_t *memb;
+ asn1p_expr_t *memb = TQ_FIRST(&expr->members);
DEPENDENCIES;
@@ -579,8 +572,6 @@
OUT("typedef struct %s {\n", MKID(expr->Identifier));
}
- memb = TQ_FIRST(&expr->members);
-
INDENT(+1);
OUT("A_%s_OF(",
(arg->expr->expr_type == ASN_CONSTR_SET_OF)
@@ -611,13 +602,13 @@
arg->embed--;
assert(arg->target->target == OT_TYPE_DECLS);
} else {
- OUT("%s", asn1c_type_name(arg, memb, TNF_CTYPE | TNF_CHECK));
+ OUT("%s", asn1c_type_name(arg, memb, TNF_RSAFE));
}
OUT(") list;\n");
INDENT(-1);
PCTX_DEF;
- OUT("} %s%s%s", expr->marker.flags?"*":"",
+ OUT("} %s%s%s", (expr->marker.flags & EM_INDIRECT)?"*":"",
expr->_anonymous_type ? "" : MKID(expr->Identifier),
arg->embed ? "" : "_t");
@@ -752,7 +743,7 @@
);
PCTX_DEF;
- OUT("} %s%s%s", expr->marker.flags?"*":"",
+ OUT("} %s%s%s", (expr->marker.flags & EM_INDIRECT)?"*":"",
expr->_anonymous_type ? "" : MKID(expr->Identifier),
arg->embed ? "" : "_t");
@@ -918,24 +909,23 @@
* refer it using "struct X" convention,
* as it may recursively include the current structure.
*/
- if(expr->marker.flags) {
+ 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)) {
- REDIR(OT_DEPS);
- tnfmt = TNF_RSAFE;
- OUT("\n");
+ tnfmt = TNF_RSAFE;
+ REDIR(OT_FWD_DECLS);
OUT("%s;\t/* Forward declaration */\n",
- asn1c_type_name(arg, arg->expr, tnfmt | TNF_CHECK));
+ asn1c_type_name(arg, arg->expr, tnfmt));
}
}
REDIR(OT_TYPE_DECLS);
- OUT("%s", asn1c_type_name(arg, arg->expr, tnfmt | TNF_CHECK));
+ OUT("%s", asn1c_type_name(arg, arg->expr, tnfmt));
if(!expr->_anonymous_type) {
- OUT("%s", expr->marker.flags?"\t*":"\t ");
+ OUT("%s", (expr->marker.flags&EM_INDIRECT)?"\t*":"\t ");
OUT("%s", MKID(expr->Identifier));
if((expr->marker.flags & EM_DEFAULT) == EM_DEFAULT)
OUT("\t/* DEFAULT %s */",
@@ -951,11 +941,10 @@
REDIR(OT_TYPE_DECLS);
OUT("typedef %s\t",
- asn1c_type_name(arg, arg->expr, TNF_CTYPE | TNF_CHECK));
+ asn1c_type_name(arg, arg->expr, TNF_CTYPE));
OUT("%s%s_t",
- expr->marker.flags?"*":" ",
- MKID(expr->Identifier));
- OUT_DEBUG("\t/* %s:%d */", __FILE__, __LINE__);
+ (expr->marker.flags & EM_INDIRECT)?"*":" ",
+ MKID_nc(expr->Identifier));
}
if((expr->expr_type == ASN_BASIC_ENUMERATED)
@@ -1557,6 +1546,47 @@
}
static int
+emit_include_dependencies(arg_t *arg) {
+ asn1p_expr_t *expr = arg->expr;
+ asn1p_expr_t *memb;
+
+ TQ_FOR(memb, &(expr->members), next) {
+
+ if((memb->meta_type == AMT_TYPEREF
+ && (memb->marker.flags & EM_INDIRECT))
+ || expr->expr_type == ASN_CONSTR_SET_OF
+ || expr->expr_type == ASN_CONSTR_SEQUENCE_OF
+ ) {
+ 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;\t/* Forward declaration */\n",
+ asn1c_type_name(arg, memb, TNF_RSAFE));
+ REDIR(saved_target);
+ memb->marker.flags |= EM_UNRECURSE;
+ }
+ }
+
+ 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;
+}
+
+static int
emit_member_table(arg_t *arg, asn1p_expr_t *expr) {
int save_target;
arg_t tmp_arg;
@@ -1576,7 +1606,8 @@
if(outmost_tag && outmost_tag->tag_value == -1)
OUT("ATF_OPEN_TYPE | ");
- OUT("%s, ", expr->marker.flags?"ATF_POINTER":"ATF_NOFLAGS");
+ OUT("%s, ",
+ (expr->marker.flags & EM_INDIRECT)?"ATF_POINTER":"ATF_NOFLAGS");
if((expr->marker.flags & EM_OPTIONAL) == EM_OPTIONAL) {
asn1p_expr_t *tv;
int opts = 0;
diff --git a/libasn1compiler/asn1c_misc.c b/libasn1compiler/asn1c_misc.c
index 94e4a63..8c5bb62 100644
--- a/libasn1compiler/asn1c_misc.c
+++ b/libasn1compiler/asn1c_misc.c
@@ -124,9 +124,6 @@
asn1c_type_name(arg_t *arg, asn1p_expr_t *expr, enum tnfmt _format) {
asn1p_expr_t *top_parent;
char *typename;
- enum ami_flags_e ami_flags = (_format & TNF_CHECK)
- ? AMI_CHECK_RESERVED : 0;
- _format &= ~TNF_CHECK;
/* Rewind to the topmost parent expression */
if((top_parent = expr->parent_expr))
@@ -152,10 +149,18 @@
return asn1c_type_name(&tmp, tmp.expr, _format);
}
+ if(_format == TNF_RSAFE) {
+ asn1p_expr_t *terminal;
+ terminal = asn1f_find_terminal_type_ex(arg->asn, expr);
+ if(terminal && terminal->expr_type & ASN_CONSTR_MASK) {
+ typename = terminal->Identifier;
+ }
+ }
+
if(_format == TNF_CTYPE) {
/*
* If the component references the type itself,
- * switch to a recursion safe type representation
+ * switch to a recursion-safe type naming
* ("struct foo" instead of "foo_t").
*/
asn1p_expr_t *terminal;
@@ -220,19 +225,14 @@
switch(_format) {
case TNF_UNMODIFIED:
case TNF_INCLUDE:
- assert(ami_flags == 0); /* (TNF_INCLUDE | TNF_CHECK)?! */
- ami_flags |= AMI_MASK_ONLY_SPACES;
- return asn1c_make_identifier(ami_flags, typename, 0);
+ return asn1c_make_identifier(AMI_MASK_ONLY_SPACES, typename, 0);
case TNF_SAFE:
- return asn1c_make_identifier(ami_flags, typename, 0);
- case TNF_CTYPE:
- return asn1c_make_identifier(ami_flags, typename, "t", 0);
- case TNF_RSAFE:
- return asn1c_make_identifier(ami_flags, "struct", " ", typename, 0);
- case TNF_NORCHECK:
- case TNF_CHECK:
- assert(_format != TNF_NORCHECK);
- assert(_format != TNF_CHECK);
+ return asn1c_make_identifier(0, typename, 0);
+ case TNF_CTYPE: /* C type */
+ return asn1c_make_identifier(0, typename, "t", 0);
+ case TNF_RSAFE: /* Recursion-safe type */
+ return asn1c_make_identifier(AMI_CHECK_RESERVED,
+ "struct", " ", typename, 0);
}
assert(!"unreachable");
diff --git a/libasn1compiler/asn1c_misc.h b/libasn1compiler/asn1c_misc.h
index c653fa8..eab7567 100644
--- a/libasn1compiler/asn1c_misc.h
+++ b/libasn1compiler/asn1c_misc.h
@@ -16,8 +16,6 @@
* Return the type name of the specified expression.
*/
enum tnfmt {
- TNF_NORCHECK = 0x00,
- TNF_CHECK = 0x01,
TNF_UNMODIFIED = 0x10, /* Return unmodified type name */
TNF_INCLUDE = 0x20, /* Format for #include <> */
TNF_CTYPE = 0x30, /* Format as normal C-ish type (append "_t") */
diff --git a/libasn1compiler/asn1c_out.c b/libasn1compiler/asn1c_out.c
index 14b1f18..46029f7 100644
--- a/libasn1compiler/asn1c_out.c
+++ b/libasn1compiler/asn1c_out.c
@@ -72,7 +72,9 @@
m->len = ret;
- if(arg->target->target == OT_INCLUDES) {
+ if(arg->target->target == OT_INCLUDES
+ || arg->target->target == OT_FWD_DECLS
+ || arg->target->target == OT_POST_INCLUDE) {
out_chunk_t *v;
TQ_FOR(v, &dst->chunks, next) {
if(m->len == v->len
diff --git a/libasn1compiler/asn1c_out.h b/libasn1compiler/asn1c_out.h
index 5a0a1f2..e500a54 100644
--- a/libasn1compiler/asn1c_out.h
+++ b/libasn1compiler/asn1c_out.h
@@ -16,8 +16,10 @@
OT_IGNORE, /* Ignore this output */
OT_INCLUDES, /* #include files */
OT_DEPS, /* Dependencies (other than #includes) */
+ OT_FWD_DECLS, /* Forward declarations */
OT_TYPE_DECLS, /* Type declarations */
OT_FUNC_DECLS, /* Function declarations */
+ OT_POST_INCLUDE,/* #include after type definition */
OT_CTABLES, /* Constraint tables */
OT_CODE, /* Some code */
OT_STAT_DEFS, /* Static definitions */
@@ -32,7 +34,7 @@
} compiler_streams_t;
static char *_compiler_stream2str[] __attribute__ ((unused))
- = { "IGNORE", "INCLUDES", "DEPS", "TYPE-DECLS", "FUNC-DECLS", "CTABLES", "CODE", "STAT-DEFS" };
+ = { "IGNORE", "INCLUDES", "DEPS", "FWD-DECLS", "TYPE-DECLS", "FUNC-DECLS", "POST-INCLUDE", "CTABLES", "CODE", "STAT-DEFS" };
int asn1c_compiled_output(arg_t *arg, const char *fmt, ...);
@@ -86,14 +88,20 @@
OUT_NOINDENT("#include <%s.h>\n", filename); \
REDIR(saved_target); \
} while(0)
+#define GEN_POSTINCLUDE(filename) do { \
+ int saved_target = arg->target->target; \
+ REDIR(OT_POST_INCLUDE); \
+ OUT_NOINDENT("#include <%s.h>\n", filename); \
+ REDIR(saved_target); \
+} while(0)
/* Generate ASN.1 type declaration */
#define GEN_DECLARE(expr) do { \
int saved_target = arg->target->target; \
- REDIR(OT_DEPS); \
+ REDIR(OT_FUNC_DECLS); \
OUT_NOINDENT("extern asn_TYPE_descriptor_t " \
"asn_DEF_%s;\n", \
- MKID(expr->Identifier)); \
+ MKID_nc(expr->Identifier)); \
REDIR(saved_target); \
} while(0)
diff --git a/libasn1compiler/asn1c_save.c b/libasn1compiler/asn1c_save.c
index 2d0410f..0f3ed04 100644
--- a/libasn1compiler/asn1c_save.c
+++ b/libasn1compiler/asn1c_save.c
@@ -222,21 +222,23 @@
fprintf(fp_h, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n");
- fprintf(fp_h, "#include <asn_application.h>\n\n");
+ fprintf(fp_h, "#include <asn_application.h>\n");
- TQ_FOR(ot, &(cs->destination[OT_INCLUDES].chunks), next) {
- asn1c_activate_dependency(deps, 0, ot->buf);
- fwrite(ot->buf, ot->len, 1, fp_h);
- }
- fprintf(fp_h, "\n");
- TQ_FOR(ot, &(cs->destination[OT_DEPS].chunks), next)
- fwrite(ot->buf, ot->len, 1, fp_h);
- fprintf(fp_h, "\n");
- TQ_FOR(ot, &(cs->destination[OT_TYPE_DECLS].chunks), next)
- fwrite(ot->buf, ot->len, 1, fp_h);
- fprintf(fp_h, "\n");
- TQ_FOR(ot, &(cs->destination[OT_FUNC_DECLS].chunks), next)
- fwrite(ot->buf, ot->len, 1, fp_h);
+#define SAVE_STREAM(idx, msg, actdep) do { \
+ if(TQ_FIRST(&(cs->destination[idx].chunks))) \
+ fprintf(fp_h, "\n/* %s */\n", msg); \
+ TQ_FOR(ot, &(cs->destination[idx].chunks), next) { \
+ if(actdep) asn1c_activate_dependency(deps, 0, ot->buf); \
+ fwrite(ot->buf, ot->len, 1, fp_h); \
+ } \
+} while(0)
+
+ SAVE_STREAM(OT_INCLUDES, "Including external dependencies", 1);
+ SAVE_STREAM(OT_DEPS, "Dependencies", 0);
+ SAVE_STREAM(OT_FWD_DECLS, "Forward declarations", 0);
+ SAVE_STREAM(OT_TYPE_DECLS, expr->Identifier, 0);
+ SAVE_STREAM(OT_FUNC_DECLS, "Implementation", 0);
+ SAVE_STREAM(OT_POST_INCLUDE, "Referred external types", 1);
fprintf(fp_h, "\n#ifdef __cplusplus\n}\n#endif\n\n"
"#endif\t/* _%s_H_ */\n",
@@ -251,7 +253,7 @@
TQ_FOR(ot, &(cs->destination[OT_STAT_DEFS].chunks), next)
fwrite(ot->buf, ot->len, 1, fp_c);
- assert(OT_MAX == 8);
+ assert(OT_MAX == 10); /* Protection from reckless changes */
fclose(fp_c);
fclose(fp_h);
diff --git a/libasn1compiler/asn1compiler.c b/libasn1compiler/asn1compiler.c
index 0159da1..107303d 100644
--- a/libasn1compiler/asn1compiler.c
+++ b/libasn1compiler/asn1compiler.c
@@ -76,9 +76,6 @@
type_cb = asn1_lang_map[expr->meta_type][expr->expr_type].type_cb;
if(type_cb) {
- if(arg->target->destination[OT_TYPE_DECLS].indent_level == 0)
- OUT("\n");
-
DEBUG("Compiling %s at line %d",
expr->Identifier,
expr->_lineno);