2 # the next line restarts using tclsh \
5 # yaz-comp: ASN.1 Compiler for YAZ
6 # (c) Index Data 1996-2000
7 # See the file LICENSE for details.
10 # Revision 1.3 2003-04-14 16:57:58 adam
11 # Add include of string.h
13 # Revision 1.2 2001/02/21 13:46:54 adam
16 # Revision 1.1 2000/03/02 08:48:20 adam
17 # Renamed ASN.1 compiler to yaz-comp (used to be yc.tcl).
19 # Revision 1.6 2000/02/10 13:44:02 adam
20 # Tcl command clock not used if unavailable (Tcl7.4 and earlier).
22 # Revision 1.5 2000/01/15 09:18:42 adam
23 # Bug fix: some elements where treated as OPTIONAL when they shouldn't.
25 # Revision 1.4 1999/12/16 23:36:19 adam
26 # Implemented ILL protocol. Minor updates ASN.1 compiler.
28 # Revision 1.3 1999/11/30 13:47:12 adam
29 # Improved installation. Moved header files to include/yaz.
31 # Revision 1.2 1999/06/09 09:43:11 adam
32 # Added option -I and variable h-path to specify path for header files.
34 # Revision 1.1 1999/06/08 10:10:16 adam
35 # New sub directory zutil. Moved YAZ Compiler to be part of YAZ tree.
37 # Revision 1.8 1999/04/20 10:37:04 adam
38 # Updated for ODR - added name parameter.
40 # Revision 1.7 1998/04/03 14:44:20 adam
43 # Revision 1.6 1998/04/03 13:21:17 adam
46 # Revision 1.5 1998/04/03 12:48:17 adam
47 # Fixed bug: missed handling of constructed tags for CHOICE.
49 # Revision 1.4 1998/03/31 15:47:45 adam
50 # First compiled ASN.1 code for YAZ.
52 # Revision 1.3 1998/03/23 17:13:20 adam
53 # Implemented SET OF and ENUM. The Compiler now eats ILL (ISO10161) and
56 # Revision 1.2 1997/10/07 10:31:01 adam
57 # Added facility to specify tag type (CONTEXT, APPLICATION, ...).
59 # Revision 1.1.1.1 1996/10/31 14:04:40 adam
60 # First version of the compiler for YAZ.
66 # Syntax for the ASN.1 supported:
69 # module -> name skip DEFINITIONS ::= mbody END
70 # mbody -> EXPORTS { nlist }
71 # | IMPORTS { imlist }
75 # type -> SEQUENCE { sqlist }
86 # sqlist -> sqlist , name tmt opt
88 # chlist -> chlist , name tmt
90 # enlist -> enlist , name (n)
92 # imlist -> nlist FROM name
93 # imlist nlist FROM name
96 # mod -> IMPLICIT | EXPLICIT | e
97 # tag -> [tagtype n] | [n] | e
100 # name identifier/token
102 # skip one token skipped
104 # tagtype APPLICATION, CONTEXT, etc.
106 # lex: moves input file pointer and returns type of token.
107 # The globals $type and $val are set. $val holds name if token
108 # is normal identifier name.
109 # sets global var type to one of:
111 # \{ left curly brace
112 # \} right curly brace
121 while {![string length $inf(str)]} {
123 set inf(cnt) [gets $inf(inf) inf(str)]
128 lappend inf(asn,$inf(asndef)) $inf(str)
129 set l [string first -- $inf(str)]
132 set inf(str) [string range $inf(str) 0 $l]
134 set inf(str) [string trim $inf(str)]
136 set s [string index $inf(str) 0]
146 \[ { regexp {^\[[ ]*(.+)[ ]*\]} $inf(str) s val }
147 : { regexp {^::=} $inf(str) s }
149 regexp "^\[^,\t :\{\}();\]+" $inf(str) s
154 set off [string length $s]
155 set inf(str) [string trim [string range $inf(str) $off end]]
159 # lex-expect: move pointer and expect token $t
160 proc lex-expect {t} {
163 if {[string compare $t $type]} {
164 asnError "Got $type '$val', expected $t"
168 # lex-name-move: see if token is $name; moves pointer and returns
169 # 1 if it is; returns 0 otherwise.
170 proc lex-name-move {name} {
172 if {![string compare $type n] && ![string compare $val $name]} {
179 # asnError: Report error and die
180 proc asnError {msg} {
183 puts "Error in line $inf(lineno) in module $inf(module)"
189 # asnWarning: Report warning and return
190 proc asnWarning {msg} {
193 puts "Warning in line $inf(lineno) in module $inf(module)"
197 # asnEnum: parses enumerated list - { name1 (n), name2 (n), ... }
198 # Uses $name as prefix. If there really is a list, $lx holds the C
199 # preprocessor definitions on return; otherwise lx isn't set.
200 proc asnEnum {name lx} {
203 if {[string compare $type \{]} return
206 set pq [asnName $name]
207 set id [lindex $pq 0]
210 lappend l "#define $inf(dprefix)$id $val"
213 if {[string compare $type ,]} break
215 if {[string compare $type \}]} {
216 asnError "Missing \} in enum list got $type '$val'"
221 # asnMod: parses tag and modifier.
222 # $xtag and $ximplicit holds tag and implicit-indication on return.
223 # $xtag is empty if no tag was specified. $ximplicit is 1 on implicit
224 # tagging; 0 otherwise.
225 proc asnMod {xtag ximplicit xtagtype} {
229 upvar $ximplicit implicit
230 upvar $xtagtype tagtype
234 if {![string compare $type \[]} {
235 if {[regexp {^([a-zA-Z]+)[ ]+([0-9]+)$} $val x tagtype tag]} {
236 set tagtype ODR_$tagtype
237 } elseif {[regexp {^([0-9]+)$} $val x tag]} {
238 set tagtype ODR_CONTEXT
240 asnError "bad tag specification: $val"
244 set implicit $inf(implicit-tags)
245 if {![string compare $type n]} {
246 if {![string compare $val EXPLICIT]} {
249 } elseif {![string compare $val IMPLICIT]} {
256 # asnName: moves pointer and expects name. Returns C-validated name.
257 proc asnName {name} {
260 if {[info exists inf(membermap,$inf(module),$name,$val)]} {
261 set nval $inf(membermap,$inf(module),$name,$val)
263 puts " mapping member $name,$val to $nval"
265 if {![string match {[A-Z]*} $val]} {
270 if {![string match {[A-Z]*} $val]} {
274 return [join [split $nval -] _]
277 # asnOptional: parses optional modifier. Returns 1 if OPTIONAL was
278 # specified; 0 otherwise.
279 proc asnOptional {} {
281 if {[lex-name-move OPTIONAL]} {
283 } elseif {[lex-name-move DEFAULT]} {
290 # asnSizeConstraint: parses the optional SizeConstraint.
291 # Currently not used for anything.
292 proc asnSizeConstraint {} {
294 if {[lex-name-move SIZE]} {
299 # asnSubtypeSpec: parses the SubtypeSpec ...
300 # Currently not used for anything. We now it's balanced however, i.e.
302 proc asnSubtypeSpec {} {
305 if {[string compare $type "("]} {
311 if {![string compare $type "("]} {
313 } elseif {![string compare $type ")"]} {
320 # asnType: parses ASN.1 type.
321 # On entry $name should hold the name we are currently defining.
322 # Returns type indicator:
323 # SequenceOf SEQUENCE OF
328 # Simple Basic types.
329 # In this casecalling procedure's $tname variable is a list holding:
330 # {C-Function C-Type} if the type is IMPORTed or ODR defined.
332 # {C-Function C-Type 1} if the type should be defined in this module
333 proc asnType {name} {
338 if {[string compare $type n]} {
339 asnError "Expects type specifier, but got $type"
346 if {[lex-name-move OF]} {
356 if {[lex-name-move OF]} {
369 if {[string length [info commands asnBasic$v]]} {
370 set tname [asnBasic$v]
372 if {[info exists inf(map,$inf(module),$v)]} {
373 set v $inf(map,$inf(module),$v)
375 if {[info exists inf(imports,$v)]} {
376 set tname $inf(imports,$v)
378 set w [join [split $v -] _]
379 set tname [list $inf(fprefix)$w $inf(vprefix)$w 1]
382 if {[lex-name-move DEFINED]} {
383 if {[lex-name-move BY]} {
391 proc mapName {name} {
393 if {[info exists inf(map,$inf(module),$name)]} {
394 set name $inf(map,$inf(module),$name)
396 puts -nonewline " $name ($inf(lineno))"
397 puts " mapping to $name"
401 puts " $name ($inf(lineno))"
407 # asnDef: parses type definition (top-level) and generates C code
408 # On entry $name holds the type we are defining.
412 set name [mapName $name]
413 if {[info exist inf(defined,$inf(fprefix)$name)]} {
414 incr inf(definedl,$name)
415 if {$inf(verbose) > 1} {
416 puts "set map($inf(module),$name) $name$inf(definedl,$name)"
419 set inf(definedl,$name) 0
421 set mname [join [split $name -] _]
422 asnMod tag implicit tagtype
423 set t [asnType $mname]
424 asnSub $mname $t $tname $tag $implicit $tagtype
428 # asnSub: parses type and generates C-code
430 # $name holds the type we are defining.
431 # $t is the type returned by the asnType procedure.
432 # $tname is the $tname set by the asnType procedure.
433 # $tag is the tag as returned by asnMod
434 # $implicit is the implicit indicator as returned by asnMod
435 proc asnSub {name t tname tag implicit tagtype} {
439 set defname defined,$inf(fprefix)$name
440 if {[info exist inf($defname)]} {
441 asnWarning "$name already defined in line $inf($defname)"
444 set inf($defname) $inf(lineno)
446 Sequence { set l [asnSequence $name $tag $implicit $tagtype] }
447 SequenceOf { set l [asnOf $name $tag $implicit $tagtype 0] }
448 SetOf { set l [asnOf $name $tag $implicit $tagtype 1] }
449 Choice { set l [asnChoice $name $tag $implicit $tagtype] }
450 Simple { set l [asnSimple $name $tname $tag $implicit $tagtype] }
451 default { asnError "switch asnType case not handled" }
456 puts $file(outc) "int $inf(fprefix)$name (ODR o, $inf(vprefix)$name **p, int opt, const char *name)"
458 puts $file(outc) [lindex $l 0]
461 set fdef "$inf(cprefix)int $inf(fprefix)$name (ODR o, $inf(vprefix)$name **p, int opt, const char *name);"
464 set decl "typedef [lindex $l 1] $inf(vprefix)$name;"
465 if {![string compare [lindex $tname 2] 1]} {
466 if {![info exist inf(defined,[lindex $tname 0])]} {
470 set inf(var,$inf(nodef)) [join [lindex $l 2] \n]
474 set decl "typedef struct $inf(vprefix)$name $inf(vprefix)$name;"
475 set inf(var,$inf(nodef)) "[lindex $l 1];"
481 puts $file(outh) $decl
482 puts $file(outh) $fdef
483 asnForwardTypes $name
485 lappend inf(forward,code,[lindex $tname 0]) {} $decl $fdef
486 lappend inf(forward,ref,[lindex $tname 0]) $name
490 proc asnForwardTypes {name} {
493 if {![info exists inf(forward,code,$inf(fprefix)$name)]} {
496 foreach r $inf(forward,code,$inf(fprefix)$name) {
499 unset inf(forward,code,$inf(fprefix)$name)
501 while {[info exists inf(forward,ref,$inf(fprefix)$name)]} {
502 set n $inf(forward,ref,$inf(fprefix)$name)
503 set m [lrange $n 1 end]
505 set inf(forward,ref,$inf(fprefix)$name) $m
507 unset inf(forward,ref,$inf(fprefix)$name)
509 asnForwardTypes [lindex $n 0]
513 # asnSimple: parses simple type definition and generates C code
515 # $name is the name we are defining
516 # $tname is the tname as returned by asnType
517 # $tag is the tag as returned by asnMod
518 # $implicit is the implicit indicator as returned by asnMod
521 # Note: Doesn't take care of enum lists yet.
522 proc asnSimple {name tname tag implicit tagtype} {
525 set j "[lindex $tname 1] "
527 if {[info exists inf(unionmap,$inf(module),$name)]} {
528 set uName $inf(unionmap,$inf(module),$name)
534 if {![string length $tag]} {
535 set l "\treturn [lindex $tname 0] (o, p, opt, name);"
536 } elseif {$implicit} {
538 "\treturn odr_implicit_tag (o, [lindex $tname 0], p, $tagtype, $tag, opt, name);"
541 "\treturn odr_explicit_tag (o, [lindex $tname 0], p, $tagtype, $tag, opt, name);" \
543 if {[info exists jj]} {
544 return [list $l $j $jj]
550 # asnSequence: parses "SEQUENCE { s-list }" and generates C code.
552 # $name is the type we are defining
557 proc asnSequence {name tag implicit tagtype} {
560 lappend j "struct $inf(vprefix)$name \{"
563 if {![string length $tag]} {
564 lappend l "\tif (!odr_sequence_begin (o, p, sizeof(**p), name))"
565 lappend l "\t\treturn opt && odr_ok (o);"
566 } elseif {$implicit} {
567 lappend l "\tif (!odr_implicit_settag (o, $tagtype, $tag) ||"
568 lappend l "\t\t!odr_sequence_begin (o, p, sizeof(**p), name))"
569 lappend l "\t\treturn opt && odr_ok(o);"
571 lappend l "\tif (!odr_constructed_begin (o, p, $tagtype, $tag, name))"
572 lappend l "\t\treturn opt && odr_ok(o);"
573 lappend l "\tif (o->direction == ODR_DECODE)"
574 lappend l "\t\t*p = ($inf(vprefix)$name *) odr_malloc (o, sizeof(**p));"
576 lappend l "\tif (!odr_sequence_begin (o, p, sizeof(**p), 0))"
578 lappend l "\t\t*p = 0;"
579 lappend l "\t\treturn 0;"
584 set p [lindex [asnName $name] 0]
585 asnMod ltag limplicit ltagtype
589 if {[info exists inf(unionmap,$inf(module),$name,$p)]} {
590 set uName $inf(unionmap,$inf(module),$name,$p)
593 if {![string compare $t Simple]} {
594 if {[string compare $uName { }]} {
600 set opt [asnOptional]
601 if {![string length $ltag]} {
602 lappend l "\t\t[lindex $tname 0](o, &(*p)->$p, $opt, \"$p\") &&"
603 } elseif {$limplicit} {
604 lappend l "\t\todr_implicit_tag (o, [lindex $tname 0],"
605 lappend l "\t\t\t&(*p)->$p, $ltagtype, $ltag, $opt, \"$p\") &&"
607 lappend l "\t\todr_explicit_tag (o, [lindex $tname 0],"
608 lappend l "\t\t\t&(*p)->$p, $ltagtype, $ltag, $opt, \"$p\") &&"
610 set dec "\t[lindex $tname 1] *$p;"
611 } elseif {![string compare $t SequenceOf] && [string length $uName] &&\
612 (![string length $ltag] || $limplicit)} {
615 if {[llength $uName] < 2} {
616 set uName [list num_$p $p]
618 if {[string length $ltag]} {
622 lappend l "\t\todr_implicit_settag (o, $ltagtype, $ltag) &&"
627 set tmpa "odr_sequence_of(o, (Odr_fun) [lindex $tname 0], &(*p)->$p,"
628 set tmpb "&(*p)->[lindex $uName 0], \"$p\")"
629 lappend j "\tint [lindex $uName 0];"
630 set dec "\t[lindex $tname 1] **[lindex $uName 1];"
633 set subName [mapName ${name}_$level]
634 asnSub $subName $u {} {} 0 {}
636 set tmpa "odr_sequence_of(o, (Odr_fun) $inf(fprefix)$subName, &(*p)->$p,"
637 set tmpb "&(*p)->[lindex $uName 0], \"$p\")"
638 lappend j "\tint [lindex $uName 0];"
639 set dec "\t$inf(vprefix)$subName **[lindex $uName 1];"
643 set opt [asnOptional]
645 lappend l "\t\t($tmpa"
646 lappend l "\t\t $tmpb || odr_ok(o)) &&"
648 lappend l "\t\t$tmpa"
649 lappend l "\t\t $tmpb &&"
651 } elseif {!$nchoice && ![string compare $t Choice] && \
652 [string length $uName]} {
653 if {[llength $uName] < 3} {
654 set uName [list which u $name]
657 lappend j "\tint [lindex $uName 0];"
658 lappend j "\tunion \{"
659 lappend v "\tstatic Odr_arm arm\[\] = \{"
660 asnArm $name [lindex $uName 2] v j
662 set dec "\t\} [lindex $uName 1];"
663 set opt [asnOptional]
666 if {[string length $ltag]} {
668 lappend l "\t\todr_implicit_settag (o, $ltagtype, $ltag) &&"
670 asnWarning "optional handling missing in CHOICE in SEQUENCE"
671 asnWarning " set unionmap($inf(module),$name,$p) to {}"
679 lappend l "\t\t${la}odr_constructed_begin (o, &(*p)->[lindex $uName 1], $ltagtype, $ltag, \"$p\") &&"
684 set ob " || odr_ok(o))"
687 lappend l "\t\t${oa}odr_choice (o, arm, &(*p)->[lindex $uName 1], &(*p)->[lindex $uName 0], 0)${ob} &&"
688 if {[string length $ltag]} {
691 set lb ") || odr_ok(o))"
695 lappend l "\t\todr_constructed_end (o)${lb} &&"
699 set subName [mapName ${name}_$level]
700 asnSub $subName $t {} {} 0 {}
701 set opt [asnOptional]
702 if {![string length $ltag]} {
703 lappend l "\t\t$inf(fprefix)${subName} (o, &(*p)->$p, $opt, \"$p\") &&"
704 } elseif {$limplicit} {
705 lappend l "\t\todr_implicit_tag (o, $inf(fprefix)${subName},"
706 lappend l "\t\t\t&(*p)->$p, $ltagtype, $ltag, $opt, \"$p\") &&"
708 lappend l "\t\todr_explicit_tag (o, $inf(fprefix)${subName},"
709 lappend l "\t\t\t&(*p)->$p, $ltagtype, $ltag, $opt, \"$p\") &&"
711 set dec "\t$inf(vprefix)${subName} *$p;"
715 lappend j "$dec /* OPT */"
719 if {[string compare $type ,]} break
722 if {[string length $tag] && !$implicit} {
723 lappend l "\t\todr_sequence_end (o) &&"
724 lappend l "\t\todr_constructed_end (o);"
726 lappend l "\t\todr_sequence_end (o);"
728 if {[string compare $type \}]} {
729 asnError "Missing \} got $type '$val'"
732 if {[info exists v]} {
735 return [list [join $l \n] [join $j \n]]
738 # asnOf: parses "SEQUENCE/SET OF type" and generates C code.
740 # $name is the type we are defining
745 proc asnOf {name tag implicit tagtype isset} {
751 set func odr_sequence_of
754 if {[info exists inf(unionmap,$inf(module),$name)]} {
755 set numName $inf(unionmap,$inf(module),$name)
757 set numName {num elements}
760 lappend j "struct $inf(vprefix)$name \{"
761 lappend j "\tint [lindex $numName 0];"
763 lappend l "\tif (!odr_initmember (o, p, sizeof(**p)))"
764 lappend l "\t\treturn opt && odr_ok(o);"
765 if {[string length $tag]} {
767 lappend l "\t/* ---- IMPLICIT ---- */"
768 lappend l "\todr_implicit_settag (o, $tagtype, $tag);"
770 asnWarning "Constructed SEQUENCE/SET OF not handled"
773 set t [asnType $name]
777 lappend l "\tif ($func (o, (Odr_fun) [lindex $tname 0], &(*p)->[lindex $numName 1],"
778 lappend l "\t\t&(*p)->[lindex $numName 0], name))"
779 lappend j "\t[lindex $tname 1] **[lindex $numName 1];"
782 set subName [mapName ${name}_s]
783 lappend l "\tif ($func (o, (Odr_fun) $inf(fprefix)$subName, &(*p)->[lindex $numName 1],"
784 lappend l "\t\t&(*p)->[lindex $numName 0], name))"
785 lappend j "\t$inf(vprefix)$subName **[lindex $numName 1];"
786 asnSub $subName $t {} {} 0 {}
790 lappend l "\t\treturn 1;"
791 lappend l "\t*p = 0;"
792 lappend l "\treturn opt && odr_ok(o);"
793 return [list [join $l \n] [join $j \n]]
796 # asnArm: parses c-list in choice
797 proc asnArm {name defname lx jx} {
803 set pq [asnName $name]
806 if {![string length $q]} {
810 asnMod ltag limplicit ltagtype
813 lappend enums "$inf(dprefix)$p"
814 if {![string compare $t Simple]} {
816 if {![string length $ltag]} {
817 lappend l "\t\t\{-1, -1, -1, $inf(dprefix)$p,"
818 lappend l "\t\t (Odr_fun) [lindex $tname 0], \"$q\"\},"
819 } elseif {$limplicit} {
820 lappend l "\t\t\{ODR_IMPLICIT, $ltagtype, $ltag, $inf(dprefix)$p,"
821 lappend l "\t\t(Odr_fun) [lindex $tname 0], \"$q\"\},"
823 lappend l "\t\t\{ODR_EXPLICIT, $ltagtype, $ltag, $inf(dprefix)$p,"
824 lappend l "\t\t(Odr_fun) [lindex $tname 0], \"$q\"\},"
826 lappend j "\t\t[lindex $tname 1] *$q;"
828 set subName [mapName ${name}_$q]
829 if {![string compare $inf(dprefix)${name}_$q \
830 $inf(vprefix)$subName]} {
831 set po [string toupper [string index $q 0]][string \
833 set subName [mapName ${name}${po}]
835 asnSub $subName $t $tname {} 0 {}
836 if {![string length $ltag]} {
837 lappend l "\t\t\{-1, -1, -1, $inf(dprefix)$p,"
838 lappend l "\t\t (Odr_fun) $inf(fprefix)$subName, \"$q\"\},"
839 } elseif {$limplicit} {
840 lappend l "\t\t\{ODR_IMPLICIT, $ltagtype, $ltag, $inf(dprefix)$p,"
841 lappend l "\t\t(Odr_fun) $inf(fprefix)$subName, \"$q\"\},"
843 lappend l "\t\t\{ODR_EXPLICIT, $ltagtype, $ltag, $inf(dprefix)$p,"
844 lappend l "\t\t(Odr_fun) $inf(fprefix)$subName, \"$q\"\},"
846 lappend j "\t\t$inf(vprefix)$subName *$q;"
848 if {[string compare $type ,]} break
850 if {[string compare $type \}]} {
851 asnError "Missing \} got $type '$val'"
856 lappend j "#define $e $level"
859 lappend l "\t\t\{-1, -1, -1, -1, (Odr_fun) 0, 0\}"
862 # asnChoice: parses "CHOICE {c-list}" and generates C code.
864 # $name is the type we are defining
869 proc asnChoice {name tag implicit tagtype} {
872 if {[info exists inf(unionmap,$inf(module),$name)]} {
873 set uName $inf(unionmap,$inf(module),$name)
875 set uName [list which u $name]
878 lappend j "struct $inf(vprefix)$name \{"
879 lappend j "\tint [lindex $uName 0];"
880 lappend j "\tunion \{"
881 lappend l "\tstatic Odr_arm arm\[\] = \{"
882 asnArm $name [lindex $uName 2] l j
883 lappend j "\t\} [lindex $uName 1];"
886 if {![string length $tag]} {
887 lappend l "\tif (!odr_initmember(o, p, sizeof(**p)))"
888 lappend l "\t\treturn opt && odr_ok(o);"
889 lappend l "\tif (odr_choice(o, arm, &(*p)->[lindex $uName 1], &(*p)->[lindex $uName 0], name))"
890 } elseif {$implicit} {
891 lappend l "\tif (!odr_initmember(o, p, sizeof(**p)))"
892 lappend l "\t\treturn opt && odr_ok(o);"
893 lappend l "\todr_implicit_settag(o, $tagtype, $tag);"
894 lappend l "\tif (odr_choice(o, arm, &(*p)->[lindex $uName 1], &(*p)->[lindex $uName 0], name))"
896 lappend l "\tif (!*p && o->direction != ODR_DECODE)"
897 lappend l "\t\treturn opt;"
898 lappend l "\tif (!odr_constructed_begin(o, p, $tagtype, $tag, 0))"
899 lappend l "\t\treturn opt && odr_ok(o);"
900 lappend l "\tif (!odr_initmember(o, p, sizeof(**p)))"
901 lappend l "\t\treturn opt && odr_ok(o);"
902 lappend l "\tif (odr_choice(o, arm, &(*p)->[lindex $uName 1], &(*p)->[lindex $uName 0], name) &&"
903 lappend l "\t\todr_constructed_end(o))"
905 lappend l "\t\treturn 1;"
906 lappend l "\t*p = 0;"
907 lappend l "\treturn opt && odr_ok(o);"
908 return [list [join $l \n] [join $j \n]]
911 # asnImports: parses i-list in "IMPORTS {i-list}"
912 # On return inf(import,..)-array is updated.
913 # inf(import,"module") is a list of {C-handler, C-type} elements.
914 # The {C-handler, C-type} is compatible with the $tname as is used by the
915 # asnType procedure to solve external references.
917 global type val inf file
920 if {[string compare $type n]} {
921 asnError "Missing name in IMPORTS list"
925 if {![string compare $type n] && ![string compare $val FROM]} {
928 if {[info exists inf(filename,$val)]} {
929 set fname $inf(filename,$val)
933 puts $file(outh) "\#include <$inf(h-dir)${fname}.h>"
935 if {[info exists inf(prefix,$val)]} {
936 set prefix $inf(prefix,$val)
938 set prefix $inf(prefix)
941 if {[info exists inf(map,$val,$n)]} {
942 set v $inf(map,$val,$n)
946 set w [join [split $v -] _]
947 set inf(imports,$n) [list [lindex $prefix 0]$w \
948 [lindex $prefix 1]$w]
952 if {[string compare $type n]} break
953 } elseif {![string compare $type ,]} {
957 if {[string compare $type \;]} {
958 asnError "Missing ; after IMPORTS list - got $type '$val'"
963 # asnExports: parses e-list in "EXPORTS {e-list}"
964 # This function does nothing with elements in the list.
969 if {[string compare $type n]} {
970 asnError "Missing name in EXPORTS list"
972 set inf(exports,$val) 1
974 if {[string compare $type ,]} break
977 if {[string compare $type \;]} {
978 asnError "Missing ; after EXPORTS list - got $type ($val)"
983 # asnModuleBody: parses a module specification and generates C code.
984 # Exports lists, imports lists, and type definitions are handled;
985 # other things are silently ignored.
986 proc asnModuleBody {} {
987 global type val file inf
989 if {[info exists inf(prefix,$inf(module))]} {
990 set prefix $inf(prefix,$inf(module))
992 set prefix $inf(prefix)
994 set inf(fprefix) [lindex $prefix 0]
995 set inf(vprefix) [lindex $prefix 1]
996 set inf(dprefix) [lindex $prefix 2]
997 if {[llength $prefix] > 3} {
998 set inf(cprefix) [lindex $prefix 3]
1000 set inf(cprefix) {YAZ_EXPORT }
1003 if {$inf(verbose)} {
1004 puts "Module $inf(module), $inf(lineno)"
1008 if {[info exists inf(init,$inf(module),c)]} {
1009 puts $file(outc) $inf(init,$inf(module),c)
1011 if {[info exists inf(init,$inf(module),h)]} {
1012 puts $file(outh) "\#ifdef __cplusplus"
1013 puts $file(outh) "extern \"C\" \{"
1014 puts $file(outh) "\#endif"
1016 puts $file(outh) $inf(init,$inf(module),h)
1018 if {[info exists inf(init,$inf(module),p)]} {
1019 puts $file(outp) $inf(init,$inf(module),p)
1022 while {[string length $type]} {
1023 if {[string compare $type n]} {
1027 if {![string compare $val END]} {
1029 } elseif {![string compare $val EXPORTS]} {
1032 } elseif {![string compare $val IMPORTS]} {
1034 puts $file(outh) "\#ifdef __cplusplus"
1035 puts $file(outh) "\}"
1036 puts $file(outh) "\#endif"
1043 puts $file(outh) "\#ifdef __cplusplus"
1044 puts $file(outh) "extern \"C\" \{"
1045 puts $file(outh) "\#endif"
1048 set inf(asndef) $inf(nodef)
1051 if {![string compare $type :]} {
1055 } elseif {![string compare $type n]} {
1057 if {[string length $type]} {
1064 puts $file(outh) "\#ifdef __cplusplus"
1065 puts $file(outh) "\}"
1066 puts $file(outh) "\#endif"
1069 foreach x [array names inf imports,*] {
1074 # asnTagDefault: parses TagDefault section
1075 proc asnTagDefault {} {
1076 global type val inf file
1078 set inf(implicit-tags) 0
1079 while {[string length $type]} {
1080 if {[lex-name-move EXPLICIT]} {
1082 set inf(implicit-tags) 0
1083 } elseif {[lex-name-move IMPLICIT]} {
1085 set inf(implicit-tags) 1
1092 # asnModules: parses a collection of module specifications.
1093 # Depending on the module pattern, $inf(moduleP), a module is either
1094 # skipped or processed.
1095 proc asnModules {} {
1096 global type val inf file yc_version
1101 while {![string compare $type n]} {
1102 set inf(module) $val
1103 if {[info exists inf(moduleP)] && ![string match $inf(moduleP) $val]} {
1104 if {$inf(verbose)} {
1107 while {![lex-name-move END]} {
1114 while {![lex-name-move DEFINITIONS]} {
1116 if {![string length $type]} return
1118 if {[info exists inf(filename,$inf(module))]} {
1119 set fname $inf(filename,$inf(module))
1121 set fname $inf(module)
1123 set ppname [join [split $fname -] _]
1125 if {![info exists inf(c-file)]} {
1126 set inf(c-file) ${fname}.c
1128 set file(outc) [open $inf(c-file) w]
1130 if {![info exists inf(h-file)]} {
1131 set inf(h-file) ${fname}.h
1133 set file(outh) [open $inf(h-path)/$inf(h-dir)$inf(h-file) w]
1136 if {![info exists inf(p-file)]} {
1137 set inf(p-file) ${fname}-p.h
1139 set file(outp) [open $inf(h-path)/$inf(h-dir)$inf(p-file) w]
1142 set greeting {Generated automatically by the YAZ ASN.1 Compiler}
1144 puts $file(outc) "/* ${greeting} ${yc_version} */"
1145 puts $file(outc) "/* Module-C: $inf(module) */"
1148 puts $file(outh) "/* ${greeting} ${yc_version} */"
1149 puts $file(outh) "/* Module-H $inf(module) */"
1152 if {[info exists file(outp)]} {
1153 puts $file(outp) "/* ${greeting} ${yc_version} */"
1154 puts $file(outp) "/* Module-P: $inf(module) */"
1158 if {[info exists inf(p-file)]} {
1159 puts $file(outc) "\#include <$inf(h-dir)$inf(p-file)>"
1161 puts $file(outc) "\#include <$inf(h-dir)$inf(h-file)>"
1163 puts $file(outh) "\#ifndef ${ppname}_H"
1164 puts $file(outh) "\#define ${ppname}_H"
1166 puts $file(outh) "\#include <$inf(h-dir)odr.h>"
1168 if {[info exists file(outp)]} {
1169 puts $file(outp) "\#ifndef ${ppname}_P_H"
1170 puts $file(outp) "\#define ${ppname}_P_H"
1172 puts $file(outp) "\#include <$inf(h-dir)$inf(h-file)>"
1177 if {[string compare $type :]} {
1178 asnError "::= expected got $type '$val'"
1181 if {![lex-name-move BEGIN]} {
1182 asnError "BEGIN expected"
1187 if {[info exists file(outp)]} {
1192 puts $f "\#ifdef __cplusplus"
1193 puts $f "extern \"C\" \{"
1195 for {set i 1} {$i < $inf(nodef)} {incr i} {
1196 puts $f $inf(var,$i)
1197 if {[info exists inf(asn,$i)]} {
1200 foreach comment $inf(asn,$i) {
1210 puts $f "\#ifdef __cplusplus"
1214 if {[info exists inf(body,$inf(module),h)]} {
1215 puts $file(outh) $inf(body,$inf(module),h)
1217 if {[info exists inf(body,$inf(module),c)]} {
1218 puts $file(outc) $inf(body,$inf(module),c)
1220 if {[info exists inf(body,$inf(module),p)]} {
1221 if {[info exists file(outp)]} {
1222 puts $file(outp) $inf(body,$inf(module),p)
1225 puts $file(outh) "\#endif"
1226 if {[info exists file(outp)]} {
1227 puts $file(outp) "\#endif"
1229 foreach f [array names file] {
1234 catch {unset inf(p-file)}
1239 # asnFile: parses an ASN.1 specification file as specified in $inf(iname).
1243 if {$inf(verbose) > 1} {
1244 puts "Reading ASN.1 file $inf(iname)"
1248 set inf(inf) [open $inf(iname) r]
1254 # The following procedures are invoked by the asnType function.
1255 # Each procedure takes the form: asnBasic<TYPE> and they must return
1256 # two elements: the C function handler and the C type.
1257 # On entry upvar $name is the type we are defining and global, $inf(module), is
1258 # the current module name.
1260 proc asnBasicEXTERNAL {} {
1261 return {odr_external {Odr_external}}
1264 proc asnBasicINTEGER {} {
1265 return {odr_integer {int}}
1268 proc asnBasicENUMERATED {} {
1269 return {odr_enum {int}}
1272 proc asnBasicNULL {} {
1273 return {odr_null {Odr_null}}
1276 proc asnBasicBOOLEAN {} {
1277 return {odr_bool {bool_t}}
1280 proc asnBasicOCTET {} {
1282 lex-name-move STRING
1283 return {odr_octetstring {Odr_oct}}
1286 proc asnBasicBIT {} {
1288 lex-name-move STRING
1289 return {odr_bitstring {Odr_bitmask}}
1292 proc asnBasicOBJECT {} {
1294 lex-name-move IDENTIFIER
1295 return {odr_oid {Odr_oid}}
1298 proc asnBasicGeneralString {} {
1299 return {odr_generalstring char}
1302 proc asnBasicVisibleString {} {
1303 return {odr_visiblestring char}
1306 proc asnBasicGeneralizedTime {} {
1307 return {odr_generalizedtime char}
1310 proc asnBasicANY {} {
1313 return [list $inf(fprefix)ANY_$name void]
1316 # userDef: reads user definitions file $name
1317 proc userDef {name} {
1320 if {$inf(verbose) > 1} {
1321 puts "Reading definitions file $name"
1325 if {[info exists default-prefix]} {
1326 set inf(prefix) ${default-prefix}
1328 if {[info exists h-path]} {
1329 set inf(h-path) ${h-path}
1331 foreach m [array names prefix] {
1332 set inf(prefix,$m) $prefix($m)
1334 foreach m [array names body] {
1335 set inf(body,$m) $body($m)
1337 foreach m [array names init] {
1338 set inf(init,$m) $init($m)
1340 foreach m [array names filename] {
1341 set inf(filename,$m) $filename($m)
1343 foreach m [array names map] {
1344 set inf(map,$m) $map($m)
1346 foreach m [array names membermap] {
1347 set inf(membermap,$m) $membermap($m)
1349 foreach m [array names unionmap] {
1350 set inf(unionmap,$m) $unionmap($m)
1355 set inf(prefix) {yc_ Yc_ YC_}
1359 # Parse command line
1360 set l [llength $argv]
1363 set arg [lindex $argv $i]
1364 switch -glob -- $arg {
1369 set p [string range $arg 2 end]
1370 if {![string length $p]} {
1371 set p [lindex $argv [incr i]]
1376 set p [string range $arg 2 end]
1377 if {![string length $p]} {
1378 set p [lindex $argv [incr i]]
1383 set p [string range $arg 2 end]
1384 if {![string length $p]} {
1385 set p [lindex $argv [incr i]]
1387 set inf(h-dir) [string trim $p \\/]/
1390 set p [string range $arg 2 end]
1391 if {![string length $p]} {
1392 set p [lindex $argv [incr i]]
1397 set p [string range $arg 2 end]
1398 if {![string length $p]} {
1399 set p [lindex $argv [incr i]]
1404 set p [string range $arg 2 end]
1405 if {![string length $p]} {
1406 set p [lindex $argv [incr i]]
1411 set p [string range $arg 2 end]
1412 if {![string length $p]} {
1413 set p [lindex $argv [incr i]]
1418 set p [string range $arg 2 end]
1419 if {![string length $p]} {
1420 set p [lindex $argv [incr i]]
1422 if {[llength $p] == 1} {
1423 set inf(prefix) [list [string tolower $p] \
1424 [string toupper $p] [string toupper $p]]
1425 } elseif {[llength $p] == 3} {
1439 if {![info exists inf(iname)]} {
1440 puts "YAZ ASN.1 Compiler ${yc_version}"
1441 puts -nonewline "Usage: ${argv0}"
1442 puts { [-v] [-c cfile] [-h hfile] [-p hfile] [-d dfile] [-I path]}
1443 puts { [-x prefix] [-m module] file}