#!/usr/bin/tclsh
#
# yaz-comp: ASN.1 Compiler for YAZ
# (c) Index Data 1996-2007
# See the file LICENSE for details.
#

set yc_version 0.4

# Syntax for the ASN.1 supported:
# file   -> file module
#         | module
# module -> name skip DEFINITIONS ::= mbody END
# mbody  -> EXPORTS { nlist }
#         | IMPORTS { imlist }
#         | name ::= tmt
#         | skip
# tmt    -> tag mod type
# type   -> SEQUENCE { sqlist }
#         | SEQUENCE OF type
#         | CHOICE { chlist }
#         | basic enlist
#
# basic  -> INTEGER
#         | BOOLEAN
#         | OCTET STRING
#         | BIT STRING
#         | EXTERNAL
#         | name
# sqlist -> sqlist , name tmt opt
#         | name tmt opt
# chlist -> chlist , name tmt 
#         | name tmt 
# enlist -> enlist , name (n)
#         | name (n)
# imlist -> nlist FROM name
#           imlist nlist FROM name
# nlist  -> name
#         | nlist , name
# mod   -> IMPLICIT | EXPLICIT | e
# tag   -> [tagtype n] | [n] | e
# opt   -> OPTIONAL | e
#
# name    identifier/token 
# e       epsilon/empty 
# skip    one token skipped
# n       number
# tagtype APPLICATION, CONTEXT, etc.

# lex: moves input file pointer and returns type of token.
# The globals $type and $val are set. $val holds name if token
# is normal identifier name.
# sets global var type to one of:
#     {}     eof-of-file
#     \{     left curly brace 
#     \}     right curly brace
#     ,      comma
#     ;      semicolon
#     (      (n)
#     [      [n]
#     :      ::=
#     n      other token n
proc lex {} {
    global inf val type
    while {![string length $inf(str)]} {
        incr inf(lineno)
        set inf(cnt) [gets $inf(inf) inf(str)]
        if {$inf(cnt) < 0} {
            set type {}
            return {}
        }
	lappend inf(asn,$inf(asndef)) $inf(str)
        set l [string first -- $inf(str)]
        if {$l >= 0} {
            incr l -1
            set inf(str) [string range $inf(str) 0 $l]
        }
        set inf(str) [string trim $inf(str)]
    }
    set s [string index $inf(str) 0]
    set type $s
    set val {}
    switch -- $s {
        \{ { }
        \} { }
        ,  { }
        ;  { }
	\(  { }
	\)  { }
        \[ { regexp {^\[[ ]*(.+)[ ]*\]} $inf(str) s val }
        :  { regexp {^::=} $inf(str) s }
        default {
             regexp "^\[^,\t :\{\}();\]+" $inf(str) s
             set type n
             set val $s
           }
    }
    set off [string length $s]
    set inf(str) [string trim [string range $inf(str) $off end]]
    return $type
}

# lex-expect: move pointer and expect token $t
proc lex-expect {t} {
    global type val
    lex
    if {[string compare $t $type]} {
        asnError "Got $type '$val', expected $t"
    }
}

# lex-name-move: see if token is $name; moves pointer and returns
# 1 if it is; returns 0 otherwise.
proc lex-name-move {name} {
    global type val
    if {![string compare $type n] && ![string compare $val $name]} {
        lex
        return 1
    }
    return 0
}

# asnError: Report error and die
proc asnError {msg} {
    global inf
   
    puts "Error in line $inf(lineno) in module $inf(module)"
    puts " $msg"
    error
    exit 1
}

# asnWarning: Report warning and return
proc asnWarning {msg} {
    global inf
   
    puts "Warning in line $inf(lineno) in module $inf(module)"
    puts " $msg"
}

# asnEnum: parses enumerated list - { name1 (n), name2 (n), ... }
# Uses $name as prefix. If there really is a list, $lx holds the C
# preprocessor definitions on return; otherwise lx isn't set.
proc asnEnum {name lx} {
    global type val inf

    if {[string compare $type \{]} return
    upvar $lx l
    while {1} {
	set pq [asnName $name]
        set id [lindex $pq 0]
	set id ${name}_$id
	lex-expect n
        lappend l "#define $inf(dprefix)$id $val"
	lex-expect ")"
        lex
        if {[string compare $type ,]} break
    }
    if {[string compare $type \}]} {
        asnError "Missing \} in enum list got $type '$val'"
    }
    lex
}

# asnMod: parses tag and modifier.
# $xtag and $ximplicit holds tag and implicit-indication on return.
# $xtag is empty if no tag was specified. $ximplicit is 1 on implicit
# tagging; 0 otherwise.
proc asnMod {xtag ximplicit xtagtype} {
    global type val inf

    upvar $xtag tag
    upvar $ximplicit implicit
    upvar $xtagtype tagtype

    set tag {} 
    set tagtype {}
    if {![string compare $type \[]} {
        if {[regexp {^([a-zA-Z]+)[ ]+([0-9]+)$} $val x tagtype tag]} {
            set tagtype ODR_$tagtype 
        } elseif {[regexp {^([0-9]+)$} $val x tag]} {
            set tagtype ODR_CONTEXT
        } else {
            asnError "bad tag specification: $val"
        }
	lex
    }
    set implicit $inf(implicit-tags)
    if {![string compare $type n]} {
        if {![string compare $val EXPLICIT]} {
            lex
            set implicit 0
        } elseif {![string compare $val IMPLICIT]} {
            lex
            set implicit 1
        }
    }
}

# asnName: moves pointer and expects name. Returns C-validated name.
proc asnName {name} {
    global val inf
    lex-expect n
    if {[info exists inf(membermap,$inf(module),$name,$val)]} {
	    set nval $inf(membermap,$inf(module),$name,$val)
	if {$inf(verbose)} {
	    puts " mapping member $name,$val to $nval"
	}
	if {![string match {[A-Z]*} $val]} {
	    lex
	}
    } else {
	set nval $val
	if {![string match {[A-Z]*} $val]} {
	    lex
	}
    }
    return [join [split $nval -] _]
}

# asnOptional: parses optional modifier                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    