1 #include "asn1fix_internal.h"
4 FTT_TYPE, /* Find the type of the given expression */
5 FTT_VALUE, /* Find the value of the given expression */
6 FTT_CONSTR_TYPE /* Find the type of the given expression having constraint */
9 static asn1p_expr_t *asn1f_find_terminal_thing(arg_t *arg, asn1p_expr_t *expr, enum ftt_what);
10 static int asn1f_compatible_with_exports(arg_t *arg, asn1p_module_t *mod, const char *name);
14 * Lookup a child by its name.
17 asn1f_lookup_child(asn1p_expr_t *tc, const char *name) {
18 asn1p_expr_t *child_tc;
20 TQ_FOR(child_tc, &(tc->members), next) {
21 if(child_tc->Identifier
22 && strcmp(child_tc->Identifier, name) == 0) {
32 asn1f_lookup_in_module(asn1p_module_t *mod, const char *name) {
33 asn1p_expr_t *expr = genhash_get(mod->members_hash, name);
36 TQ_FOR(memb, &mod->members, next) {
37 if(memb->expr_type == ASN_BASIC_ENUMERATED) {
38 asn1p_expr_t *v = asn1f_lookup_child(memb, name);
48 asn1f_lookup_in_imports(arg_t *arg, asn1p_module_t *mod, const char *name) {
52 * Search in which exactly module this name is defined.
54 TQ_FOR(xp, &(mod->imports), xp_next) {
55 asn1p_module_t *fromModule =
56 asn1f_lookup_module(arg, xp->fromModuleName, NULL);
57 asn1p_expr_t *tc = (asn1p_expr_t *)0;
59 TQ_FOR(tc, &(xp->xp_members), next) {
60 if(strcmp(name, tc->Identifier) == 0)
67 asn1f_lookup_in_module(fromModule, name);
78 * Okay, right now we have a module name and, hopefully, an OID.
79 * Search the arg->asn for the specified module.
81 mod = asn1f_lookup_module(arg, xp->fromModuleName, xp->identifier.oid);
83 /* Conditional debug */
84 if(!(arg->expr->_mark & TM_BROKEN)) {
85 arg->expr->_mark |= TM_BROKEN;
86 FATAL("Cannot find external module \"%s\" "
89 "Obtain this module and instruct compiler to process it too.",
90 xp->fromModuleName, name, arg->expr->_lineno);
92 /* ENOENT/ETOOMANYREFS */
97 * Check that the EXPORTS section of this module contains
98 * the symbol we care about, or it is EXPORTS ALL.
100 if(asn1f_compatible_with_exports(arg, mod, name)) {
109 asn1f_lookup_module(arg_t *arg, const char *module_name, const asn1p_oid_t *oid) {
115 * If OID is given, the module_name is unused.
116 * If OID is not given, the module_name may mean
117 * either the real module's name, or the symbol which is the
118 * result of renaming. Check this first.
123 * Check inside the IMPORTS section for possible renaming.
124 * Renaming practically means that a module_name is mentioned
125 * somewhere in the IMPORTS section AND OID is given.
127 TQ_FOR(xp, &(arg->mod->imports), xp_next) {
128 if(strcmp(module_name, xp->fromModuleName))
131 FATAL("Ambiguous reference: "
133 "matches several modules",
135 errno = ETOOMANYREFS;
139 * Yes, there is a renaming.
140 * Make lookup use OID instead.
142 oid = xp->identifier.oid;
147 * Perform lookup using OID or module_name.
149 TQ_FOR(mod, &(arg->asn->modules), mod_next) {
151 if(mod->module_oid) {
152 if(asn1p_oid_compare(oid,
156 /* Match! Even if name doesn't. */
160 /* Not match, even if name is the same. */
165 if(strcmp(module_name, mod->ModuleName) == 0)
169 DEBUG("\tModule \"%s\" not found", module_name);
175 static asn1p_expr_t *
176 asn1f_lookup_symbol_impl(arg_t *arg, asn1p_expr_t *rhs_pspecs, const asn1p_ref_t *ref, int recursion_depth) {
177 asn1_namespace_t *initial_namespace = arg->ns;
179 asn1p_module_t *imports_from;
183 if(ref->module && arg->mod != ref->module) {
186 asn1f_lookup_symbol_impl(arg, rhs_pspecs, ref, recursion_depth));
190 * First of all, a reference to a symbol may be specified
191 * using several possible forms:
192 * a) simple identifier
193 * v INTEGER ::= value
194 * b) external reference
195 * v INTEGER ::= Module1.value
196 * c) class-related stuff (the most complex stuff)
197 * v ::= <[A-Z][A-Z0-9a-z-]*>.&<[A-Z0-9a-z-]+>.
198 * All other forms are not implemented at this moment.
201 DEBUG("Lookup (%s) in %s for line %d",
202 asn1f_printable_reference(ref),
203 asn1_namespace_string(initial_namespace),
206 if(recursion_depth++ > 30 /* Arbitrary constant */) {
208 "Excessive circular referencing detected in namespace %s for %s at "
210 asn1_namespace_string(initial_namespace),
211 asn1f_printable_reference(ref), ref->_lineno);
212 errno = ETOOMANYREFS;
216 if(ref->comp_count == 1) {
218 identifier = ref->components[0].name;
219 } else if(ref->comp_count == 2
220 && ref->components[1].name[0] != '&') {
221 modulename = ref->components[0].name;
222 identifier = ref->components[1].name;
223 } else if(ref->comp_count > 1
224 && isupper(ref->components[0].name[0])
225 && ref->components[1].name[0] == '&') {
226 asn1p_expr_t *extract;
228 * This is a reference to a CLASS-related stuff.
229 * Employ a separate function for that.
231 extract = asn1f_class_access(arg, rhs_pspecs, ref);
235 DEBUG("\tToo many components: %d", ref->comp_count);
242 * The modulename is specified inside this reference.
243 * To avoid recursion, reformat the reference
244 * as it were local to that module.
247 tmp_ref.components++; /* Hide the first element */
248 tmp_ref.comp_count--;
249 assert(tmp_ref.comp_count > 0);
253 asn1_namespace_t *my_namespace = initial_namespace;
255 #define DISPOSE_OF_MY_NAMESPACE() \
257 int tmp_errno = errno; \
258 if(my_namespace != initial_namespace) { \
259 asn1_namespace_free(my_namespace); \
260 my_namespace = NULL; \
266 * If module name is specified explicitly
267 * OR the current module's IMPORTS clause contains the identifier,
268 * switch namespace to that module.
271 imports_from = asn1f_lookup_module(arg, modulename, 0);
272 if(imports_from == NULL) {
275 "mentioned at line %d is not found",
276 modulename, ref->_lineno);
281 * Check that the EXPORTS section of this module contains
282 * the symbol we care about, or it is EXPORTS ALL.
284 if(asn1f_compatible_with_exports(arg, imports_from, identifier)) {
289 DISPOSE_OF_MY_NAMESPACE();
290 my_namespace = asn1_namespace_new_from_module(imports_from, 1);
291 DEBUG("Lookup (%s) in %s for line %d", asn1f_printable_reference(ref),
292 asn1_namespace_string(my_namespace), ref->_lineno);
295 size_t namespace_switches = 0;
298 * Search through all layers of the namespace.
300 for(ssize_t ns_item = my_namespace->elements_count - 1; ns_item >= 0;
302 struct asn1_namespace_element_s *ns_el =
303 &my_namespace->elements[ns_item];
305 switch(ns_el->selector) {
309 * Trying to match a fully specified "Module.Symbol"
310 * against the "Symbol" parameter. Doesn't match.
314 if(strcmp(ns_el->u.symbol.identifier, identifier) != 0) {
317 DEBUG("Lookup (%s) in %s for line %d => found as parameter",
318 asn1f_printable_reference(ref),
319 asn1_namespace_string(my_namespace), ref->_lineno);
320 DISPOSE_OF_MY_NAMESPACE();
321 return ns_el->u.symbol.resolution;
324 asn1p_expr_t *ref_tc; /* Referenced tc */
326 * Do a direct symbol search in the given module.
328 ref_tc = asn1f_lookup_in_module(ns_el->u.space.module, identifier);
330 /* It is acceptable that we don't use input parameters */
331 if(rhs_pspecs && !ref_tc->lhs_params) {
333 "Parameterized type %s expected "
335 ref_tc->Identifier, asn1f_printable_reference(ref),
338 if(!rhs_pspecs && ref_tc->lhs_params) {
340 "Type %s expects specialization "
341 "from %s at line %d",
342 ref_tc->Identifier, asn1f_printable_reference(ref),
345 DISPOSE_OF_MY_NAMESPACE();
348 if(rhs_pspecs && ref_tc->lhs_params) {
349 /* Specialize the target */
351 asn1f_parameterization_fork(arg, ref_tc, rhs_pspecs);
354 DISPOSE_OF_MY_NAMESPACE();
360 if(!expr && !(arg->expr->_mark & TM_BROKEN)
361 && !(imports_from->_tags & MT_STANDARD_MODULE)) {
362 arg->expr->_mark |= TM_BROKEN;
366 "Module %s referred in IMPORTS section "
367 "for %s of module %s does not contain "
368 "the requested symbol",
369 imports_from->ModuleName,
370 asn1f_printable_reference(ref), mod->ModuleName);
375 /* Search inside the IMPORTS section of the given module */
377 asn1f_lookup_in_imports(arg, ns_el->u.space.module, identifier);
380 if(namespace_switches++ > 10 /* Arbitrary constant */) {
382 "Excessive circular referencing detected in namespace "
385 asn1_namespace_string(arg->ns),
386 asn1f_printable_reference(ref), ref->_lineno);
387 errno = ETOOMANYREFS;
388 DISPOSE_OF_MY_NAMESPACE();
392 /* Switch namespace */
393 DISPOSE_OF_MY_NAMESPACE();
394 my_namespace = asn1_namespace_new_from_module(imports_from, 1);
395 DEBUG("Lookup (%s) in %s for line %d",
396 asn1f_printable_reference(ref),
397 asn1_namespace_string(my_namespace), ref->_lineno);
398 ns_item = my_namespace->elements_count;
401 } else if(errno != ESRCH) {
403 * Return only if the name was not found.
404 * If module was not found or more serious error
405 * encountered, just return preserving the errno.
407 DISPOSE_OF_MY_NAMESPACE();
413 "Module %s referred by %s in module %s "
414 "does not contain the requested symbol",
415 ns_el->u.space.module->ModuleName,
416 asn1f_printable_reference(ref), modulename);
420 /* Search failed in the given namespace */
426 "Namespace %s does not contain \"%s\" "
427 "mentioned at line %d: %s",
428 asn1_namespace_string(my_namespace), identifier, ref->_lineno,
431 DISPOSE_OF_MY_NAMESPACE();
433 if(asn1f_check_known_external_type(identifier) == 0) {
434 errno = EEXIST; /* Exists somewhere */
443 asn1f_lookup_symbol(arg_t *arg, asn1p_expr_t *rhs_pspecs,
444 const asn1p_ref_t *ref) {
445 return asn1f_lookup_symbol_impl(arg, rhs_pspecs, ref, 0);
449 asn1f_find_terminal_type(arg_t *arg, asn1p_expr_t *expr) {
450 return asn1f_find_terminal_thing(arg, expr, FTT_TYPE);
454 asn1f_find_terminal_value(arg_t *arg, asn1p_expr_t *expr) {
455 return asn1f_find_terminal_thing(arg, expr, FTT_VALUE);
459 asn1f_find_ancestor_type_with_PER_constraint(arg_t *arg, asn1p_expr_t *expr) {
460 return asn1f_find_terminal_thing(arg, expr, FTT_CONSTR_TYPE);
463 static asn1p_expr_t *
464 asn1f_find_terminal_thing(arg_t *arg, asn1p_expr_t *expr, enum ftt_what what) {
465 asn1p_ref_t *ref = 0;
468 if(arg->mod != expr->module) {
469 return WITH_MODULE(expr->module,
470 asn1f_find_terminal_thing(arg, expr, what));
475 case FTT_CONSTR_TYPE:
476 /* Expression may be a terminal type itself */
477 if(expr->expr_type != A1TC_REFERENCE) {
480 ref = expr->reference;
484 DEBUG("%s(%s->%s) meta %d for line %d",
485 "VALUE", expr->Identifier, asn1f_printable_reference(ref),
486 expr->meta_type, expr->_lineno);
488 assert(expr->meta_type == AMT_VALUE);
490 /* Expression may be a terminal type itself */
491 if(expr->value->type != ATV_REFERENCED) {
494 ref = expr->value->value.reference;
498 DEBUG("%s(%s->%s) for line %d",
499 (what == FTT_VALUE)?"VALUE":"TYPE",
500 expr->Identifier, asn1f_printable_reference(ref),
506 * Lookup inside the type itself (ENUMERATED, INTEGER, etc).
508 if(what == FTT_VALUE) {
509 asn1p_expr_t *val_type_tc;
510 val_type_tc = asn1f_find_terminal_type(arg, expr);
512 && WITH_MODULE(val_type_tc->module,
513 asn1f_look_value_in_type(arg, val_type_tc, expr))) {
516 if(expr->value->type != ATV_REFERENCED) {
519 assert(ref == expr->value->value.reference);
520 ref = expr->value->value.reference;
524 * Lookup inside the default module and its IMPORTS section.
526 tc = asn1f_lookup_symbol(arg, expr->rhs_pspecs, ref);
529 * Lookup inside the ref's module and its IMPORTS section.
531 tc = WITH_MODULE(ref->module,
532 asn1f_lookup_symbol(arg, expr->rhs_pspecs, ref));
534 DEBUG("\tSymbol \"%s\" not found: %s",
535 asn1f_printable_reference(ref),
542 * Recursive loops detection.
544 if(tc->_mark & TM_RECURSION) {
545 DEBUG("Recursion loop detected for %s at line %d",
546 asn1f_printable_reference(ref), ref->_lineno);
551 tc->_type_referenced = 1;
553 if((what == FTT_CONSTR_TYPE) && (tc->constraints)) {
557 tc->_mark |= TM_RECURSION;
558 expr = WITH_MODULE(tc->module, asn1f_find_terminal_thing(arg, tc, what));
559 tc->_mark &= ~TM_RECURSION;
566 * Make sure that the specified name is present or otherwise does
567 * not contradict with the EXPORTS clause of the specified module.
570 asn1f_compatible_with_exports(arg_t *arg, asn1p_module_t *mod, const char *name) {
571 asn1p_xports_t *exports;
577 exports = TQ_FIRST(&(mod->exports));
578 if(exports == NULL) {
579 /* No EXPORTS section or EXPORTS ALL; */
583 TQ_FOR(item, &(exports->xp_members), next) {
584 if(strcmp(item->Identifier, name) == 0)
588 /* Conditional debug */
589 if(!(arg->expr->_mark & TM_BROKEN)) {
590 arg->expr->_mark |= TM_BROKEN;
591 FATAL("EXPORTS section of module %s in %s "
592 "does not mention %s at line %d",
593 mod->ModuleName, mod->source_file_name, name,