asn1compiler.c 5.06 KB
Newer Older
Lev Walkin's avatar
Lev Walkin committed
1
#include "asn1c_internal.h"
2 3 4
#include "asn1c_lang.h"
#include "asn1c_out.h"
#include "asn1c_save.h"
5
#include "asn1c_ioc.h"
6
#include "asn1c_naming.h"
Lev Walkin's avatar
Lev Walkin committed
7 8

static void default_logger_cb(int, const char *fmt, ...);
9
static int asn1c_compile_expr(arg_t *arg, const asn1c_ioc_table_and_objset_t *);
Lev Walkin's avatar
Lev Walkin committed
10
static int asn1c_attach_streams(asn1p_expr_t *expr);
11
static int asn1c_detach_streams(asn1p_expr_t *expr);
Lev Walkin's avatar
Lev Walkin committed
12 13

int
Lev Walkin's avatar
Lev Walkin committed
14
asn1_compile(asn1p_t *asn, const char *datadir, enum asn1c_flags flags,
Lev Walkin's avatar
Lev Walkin committed
15
		int argc, int optc, char **argv) {
Lev Walkin's avatar
Lev Walkin committed
16 17
	arg_t arg_s;
	arg_t *arg = &arg_s;
Lev Walkin's avatar
Lev Walkin committed
18
	asn1p_module_t *mod;
Lev Walkin's avatar
Lev Walkin committed
19 20
	int ret;

21 22
	c_name_clash_finder_init();

Lev Walkin's avatar
Lev Walkin committed
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
	/*
	 * Initialize target language.
	 */
	ret = asn1c_with_language(ASN1C_LANGUAGE_C);
	assert(ret == 0);

	memset(arg, 0, sizeof(*arg));
	arg->default_cb = asn1c_compile_expr;
	arg->logger_cb = default_logger_cb;
	arg->flags = flags;
	arg->asn = asn;

	/*
	 * Compile each individual top level structure.
	 */
Lev Walkin's avatar
Lev Walkin committed
38 39
	TQ_FOR(mod, &(asn->modules), mod_next) {
		TQ_FOR(arg->expr, &(mod->members), next) {
Lev Walkin's avatar
Lev Walkin committed
40 41
			arg->ns = asn1_namespace_new_from_module(mod, 0);

Lev Walkin's avatar
Lev Walkin committed
42 43 44 45 46 47 48 49 50
			compiler_streams_t *cs = NULL;

			if(asn1c_attach_streams(arg->expr))
				return -1;

			cs = arg->expr->data;
			cs->target = OT_TYPE_DECLS;
			arg->target = cs;

51
			ret = asn1c_compile_expr(arg, NULL);
Lev Walkin's avatar
Lev Walkin committed
52
			if(ret) {
53
				FATAL("Cannot compile \"%s\" (%x:%x) at line %d",
Lev Walkin's avatar
Lev Walkin committed
54 55 56 57 58 59
					arg->expr->Identifier,
					arg->expr->expr_type,
					arg->expr->meta_type,
					arg->expr->_lineno);
				return ret;
			}
Lev Walkin's avatar
Lev Walkin committed
60 61 62

			asn1_namespace_free(arg->ns);
			arg->ns = 0;
Lev Walkin's avatar
Lev Walkin committed
63 64 65
		}
	}

66 67 68 69 70 71 72 73 74 75 76 77 78 79
	if(c_name_clash(arg)) {
		if(arg->flags & A1C_COMPOUND_NAMES) {
			FATAL("Name clashes encountered even with -fcompound-names flag");
			/* Proceed further for better debugging. */
		} else {
			FATAL("Use \"-fcompound-names\" flag to asn1c to resolve name clashes");
			if(arg->flags & A1C_PRINT_COMPILED) {
				/* Proceed further for better debugging. */
			} else {
				return -1;
			}
		}
	}

Lev Walkin's avatar
Lev Walkin committed
80 81
	DEBUG("Saving compiled data");

82 83
	c_name_clash_finder_destroy();

Lev Walkin's avatar
Lev Walkin committed
84 85 86
	/*
	 * Save or print out the compiled result.
	 */
Lev Walkin's avatar
Lev Walkin committed
87
	if(asn1c_save_compiled_output(arg, datadir, argc, optc, argv))
Lev Walkin's avatar
Lev Walkin committed
88 89
		return -1;

90 91 92 93 94 95
	TQ_FOR(mod, &(asn->modules), mod_next) {
		TQ_FOR(arg->expr, &(mod->members), next) {
			asn1c_detach_streams(arg->expr);
		}
	}

Lev Walkin's avatar
Lev Walkin committed
96 97 98 99
	return 0;
}

static int
100
asn1c_compile_expr(arg_t *arg, const asn1c_ioc_table_and_objset_t *opt_ioc) {
Lev Walkin's avatar
Lev Walkin committed
101 102 103 104
	asn1p_expr_t *expr = arg->expr;
	int (*type_cb)(arg_t *);
	int ret;

105
	assert((int)expr->meta_type >= AMT_INVALID);
Lev Walkin's avatar
Lev Walkin committed
106
	assert(expr->meta_type < AMT_EXPR_META_MAX);
107
	assert((int)expr->expr_type >= A1TC_INVALID);
Lev Walkin's avatar
Lev Walkin committed
108 109 110 111 112 113 114 115 116
	assert(expr->expr_type < ASN_EXPR_TYPE_MAX);

	type_cb = asn1_lang_map[expr->meta_type][expr->expr_type].type_cb;
	if(type_cb) {

		DEBUG("Compiling %s at line %d",
			expr->Identifier,
			expr->_lineno);

117 118 119 120 121 122
		if(expr->lhs_params && expr->spec_index == -1) {
			int i;
			ret = 0;
			DEBUG("Parameterized type %s at line %d: %s (%d)",
				expr->Identifier, expr->_lineno,
				expr->specializations.pspecs_count
123 124
				? "compiling" : "unused, skipping",
				expr->specializations.pspecs_count);
125 126 127
			for(i = 0; i<expr->specializations.pspecs_count; i++) {
				arg->expr = expr->specializations
						.pspec[i].my_clone;
128
				ret = asn1c_compile_expr(arg, opt_ioc);
129 130 131 132 133 134 135 136 137
				if(ret) break;
			}
			arg->expr = expr;	/* Restore */
		} else {
			ret = type_cb(arg);
			if(arg->target->destination[OT_TYPE_DECLS]
					.indent_level == 0)
				OUT(";\n");
		}
Lev Walkin's avatar
Lev Walkin committed
138 139 140 141 142 143 144 145 146
	} else {
		ret = -1;
		/*
		 * Even if the target language compiler does not know
		 * how to compile the given expression, we know that
		 * certain expressions need not to be compiled at all.
		 */
		switch(expr->meta_type) {
		case AMT_OBJECT:
147 148
		case AMT_OBJECTCLASS:
		case AMT_OBJECTFIELD:
Lev Walkin's avatar
Lev Walkin committed
149 150 151 152 153 154 155 156 157 158
		case AMT_VALUE:
		case AMT_VALUESET:
			ret = 0;
			break;
		default:
			break;
		}
	}

	if(ret == -1) {
Lev Walkin's avatar
Lev Walkin committed
159 160 161 162 163
		FATAL("Cannot compile \"%s\" (%x:%x) at line %d",
			arg->expr->Identifier,
			arg->expr->expr_type,
			arg->expr->meta_type,
			arg->expr->_lineno);
Lev Walkin's avatar
Lev Walkin committed
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
		OUT("#error Cannot compile \"%s\" (%x/%x) at line %d\n",
			arg->expr->Identifier,
			arg->expr->meta_type,
			arg->expr->expr_type,
			arg->expr->_lineno
		);
	}

	return ret;
}

static int
asn1c_attach_streams(asn1p_expr_t *expr) {
	compiler_streams_t *cs;
	int i;

	if(expr->data)
		return 0;	/* Already attached? */

	expr->data = calloc(1, sizeof(compiler_streams_t));
	if(expr->data == NULL)
		return -1;

	cs = expr->data;
	for(i = 0; i < OT_MAX; i++) {
189
		TQ_INIT(&(cs->destination[i].chunks));
Lev Walkin's avatar
Lev Walkin committed
190 191 192 193 194
	}

	return 0;
}

195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
int
asn1c_detach_streams(asn1p_expr_t *expr) {
	compiler_streams_t *cs;
	out_chunk_t *m;
	int i;

	if(!expr->data)
		return 0;	/* Already detached? */

	cs = expr->data;
	for(i = 0; i < OT_MAX; i++) {
		while((m = TQ_REMOVE(&(cs->destination[i].chunks), next))) {
			free(m->buf);
			free(m);
		}
	}
	free(expr->data);
	expr->data = (void *)NULL;

	return 0;
}

Lev Walkin's avatar
Lev Walkin committed
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
static void
default_logger_cb(int _severity, const char *fmt, ...) {
	va_list ap;
	char *pfx = "";

	switch(_severity) {
	case -1: pfx = "DEBUG: "; break;
	case 0: pfx = "WARNING: "; break;
	case 1: pfx = "FATAL: "; break;
	}

	fprintf(stderr, "%s", pfx);
	va_start(ap, fmt);
	vfprintf(stderr, fmt, ap);
	va_end(ap);
	fprintf(stderr, "\n");
}