[BACK]Return to libspec.awk CVS log [TXT][DIR] Up to [Development] / projects / ogl-sample / main / tools / libspec

File: [Development] / projects / ogl-sample / main / tools / libspec / libspec.awk (download)

Revision 1.1.1.1 (vendor branch), Wed Jan 26 10:31:14 2000 UTC (17 years, 9 months ago) by ljp
Branch: SGI
CVS Tags: oglsi1_2_1
Changes since 1.1: +0 -0 lines

Imported from P4

##############################################################################
#
# License Applicability. Except to the extent portions of this file are
# made subject to an alternative license as permitted in the SGI Free
# Software License B, Version 1.0 (the "License"), the contents of this
# file are subject only to the provisions of the License. You may not use
# this file except in compliance with the License. You may obtain a copy
# of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
# Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
# 
# http://oss.sgi.com/projects/FreeB
# 
# Note that, as provided in the License, the Software is distributed on an
# "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
# DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
# CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
# PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
# 
# Original Code. The Original Code is: OpenGL Sample Implementation,
# Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
# Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
# Copyright in any portions created by third parties is as indicated
# elsewhere herein. All Rights Reserved.
# 
# Additional Notice Provisions: The application programming interfaces
# established by SGI in conjunction with the Original Code are The
# OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
# April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
# 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
# Window System(R) (Version 1.3), released October 19, 1998. This software
# was created using the OpenGL(R) version 1.2.1 Sample Implementation
# published by SGI, but has not been independently verified as being
# compliant with the OpenGL(R) version 1.2.1 Specification.
#
#  NAME
#	libspec.awk - specfile parsing awk script used by libspec
#
#  DESCRIPTION
#	This awk script parses the libspec format for each function interface,
#	generates values for a set of global variables, and then calls the
#	user program's function main() for generating output.  The main()
#	function gets the information it needs about the function from the
#	global variables.
#
#  AUTHOR
#	Dave Ciemiewicz (ciemo)
#	Gary Tarolli (gt)
#	David Mott (mott) - added checkparam and reqstates for gldebug 3/90
#
##############################################################################


##############################################################################
#
#  SECTION
#	Initialization
#
#  DESCRIPTION
#	Initialize useful constants.
#	Do the user's initialization and check it.
#	Initialize parsing.
#
#  SETS
#	true			-- Boolean value constant
#	false			-- Boolean value constant
#	stderr			-- For piping print[f] output to stderr
#	stripcomments		-- Strip commments from file for getline reads
#	validDirections		-- Set of valid directions
#	validTransferTypes	-- Set of valid transfer types
#
##############################################################################
BEGIN {
    true = 1
    false = 0

    validDirections["in"]
    validDirections["out"]
    validDirections["inout"]

    validTransferTypes["value"]
    validTransferTypes["reference"]
    validTransferTypes["array"]


    # 
    #	Special file methods
    #
    # Pipe to stderr on print or printf line
    stderr = "cat 1>&2"
    # sed script to remove comments from .map file
    stripcomments = "sed -e '/^[ \t]*\#/d' -e '/^[ \t]*$/d' -e 's/[ \t]*\#.*$//' "

    #
    #	Do user's initialization.
    #
    initialize()

    #
    #	Check if user initialized everything needed
    #
    if (typeMapArg != "") {
	typeMapFile = typeMapArg
    }
    if (typeMapPath != "") {
	typeMapFile = typeMapPath "/" typeMapFile
    }
    if (typeMapFile == "") {
	readError(libspecProgram,"no typeMapFile was specified in initialize()")
	exit 1
    }
    _readTypeMap(typeMapFile)
    _resetParseStates()
}

# END Initialization

##############################################################################
#
#  SECTION
#	Parser pattern-actions
#
#  DESCRIPTION
#	The following awk pattern-action statements match input lines from
#	the spec file and call the appropriate parsing functions to parse the
#	lines.  If the parsing function is trivial, then it is in-line coded
#
#  SPEC FILE BNF
#	<spec-file> :== <declaration-line>* <function-description>*
#	<declaration-line> :== <required-props-declaration> |
#				<valid-props-declaration>
#	<function-description> :== <function-prototype> <prop-lines>
#				   <end-of-function-description>
#
#	<return-prop-line> ::= <prop-indent> <return-prop>
#	<return-prop> ::= "return" <blank> <unmapped-return-type>
#
#	<param-prop-line> ::= <prop-indent> <param-prop>
#	<param-prop> ::= "param" <blank> <param-prop-body>
#
#	<prop-line> ::= <prop-indent> <prop-name> <meta-prop-value>*
#
##############################################################################
# NOTE: the following are ordered for optimal performance


##############################################################################
#
#  Parse comment lines and comments from spec file
#
#  SPEC FILE BNF
#	<comment-line> ::= <comment>
#	<comment> ::= <blank> "#" <text-upto-newline> 
#
##############################################################################
/^[ \t]*#/ {next}		# Do this so it is not treated as a blank line.
{ sub(/[ \t]*#.*$/, "") }	# Trim off trailing comment.  The sub forces
				# awk to recompute NF automatically.

##############################################################################
#
#  Parse return prop
#
#  SPEC FILE BNF
#	<return-prop-line> ::= <prop-indent> <return-prop>
#	<return-prop> ::= "return" <blank> <unmapped-return-type>
#
##############################################################################
($1 == "return") {
    _parseReturnType()
    _parsedReturn = true
    next
}


##############################################################################
#
#  Parse param prop
#
#  SPEC FILE BNF
#	<param-prop-line> ::= <prop-indent> <param-prop>
#	<param-prop> ::= "param" <blank> <param-prop-body>
#
##############################################################################
($1 == "param") {
    _parseParamPropBody()
    next
}


##############################################################################
#
#  Parse prop lines
#
#  SPEC FILE BNF
#	<prop-line> ::= <prop-indent> <prop-name> <meta-prop-value>*
#
##############################################################################
/^\t/	{
    _parseProp()
    delete _unparsedRequiredProps[$1]	# Check off required props when parsed
    next
}


##############################################################################
#
#  Parse function prototype
#
#  SPEC FILE BNF
#	<function-prototype> :== <function-name> "(" <param-list> ")"
#
##############################################################################
/^[^\t]*\(/ {
    _parseFunctionPrototype()
    _parsedPrototype = true

    # setup list to determine which props haven't yet been parsed for function
    for (i in requiredProps) {
	_unparsedRequiredProps[i]
    }
    next
}


##############################################################################
#
#  Parse end of function description
#
#  SPEC FILE BNF
#	<end-of-function-description> ::= ( <empty-line> | <end-of-file> )
#
##############################################################################
/^$/ {
    if (!_parsingErrors()) {
    	main()		# User's main routine
    }
    _resetParseStates()
    clearArray(propList)
    clearArray(propListValues)
    clearArray(paramName)
    clearArray(paramList)
    clearArray(paramUnmappedDeclaredType)
    clearArray(paramUnmappedDirection)
    clearArray(paramUnmappedTransferType)
    clearArray(paramDeclaredType)
    clearArray(paramDirection)
    clearArray(paramTransferType)
    clearArray(paramDimensions)
    clearArray(paramSubscripts)
    clearArray(paramOptions)

    # mott - begin additions for gldebug
    statesMustBeIn = ""
    statesMustNotBeIn = ""
    clearArray(checkparamProps)
    clearArray(reqstatesSeverity)
    clearArray(checkparamSeverity)
    clearArray(paramLowerBoundValue)
    clearArray(paramLowerBoundRange)
    clearArray(paramUpperBoundValue)
    clearArray(paramUpperBoundRange)

    clearArray(checkparamSetSize)
    clearArray(checkparamOneOfSet)
    clearArray(severityCountReqstates)
    clearArray(severityCountCheckparam)
    # mott - end

    next
}


##############################################################################
#
#  Parse required props declaration
#
#  SPEC FILE BNF
#	<required-props-declaration> ::= "required-props:"<required-prop-list>
#	<required-prop-list> ::= (<blank> <prop-name>)*
#
#  SETS
#	requiredProps[propName] -- Set of required props
#
##############################################################################
/^required-props:/ {
    for (i=2; i<=NF; i++) {
	requiredProps[$i]
    }
    next
}

##############################################################################
#
#  Parse valid props declarations
#
#  SPEC FILE BNF
#	<valid-props-declaration> ::= <prop-name> ":" <prop-values>
#
##############################################################################
/^[^ 	]*:/ {
    _parseValidPropsDeclaration()
    next
}


END {
    if (!_parsingErrors()) {
    	main()		# User's main routine
    }
    finalize()
}

# END Parser pattern-actions

##############################################################################
#
#  Parsing functions
#
##############################################################################


##############################################################################
#
#  NAME
#	_parseValidPropsDeclaration()
#
#  SPEC FILE BNF
#	<valid-props-declaration> ::= <prop-name> ":" <prop-values>
#	<prop-values> ::= (<blank> <prop-value>)*
#
#  SETS
#	validPropList[propname]	-- Set of valid props
#				-- ... [] is a comma separated list of
#				-- ... valid prop values
#	validPropListValues[propname,value]
#				-- Set of valid (propname,values)
#
#	_parseErrorOccured	-- Flag indicating error in parsing
#
##############################################################################
function _parseValidPropsDeclaration(	i) {
    gsub(/:/, "", $1)		# Get rid of colon from list name
    for (i=2; i<=NF; i++) {
	if (! (($1,$i) in validPropListValues)) {
	    validPropListValues[$1, $i]
	    validPropList[$1] = validPropList[$1] "," $i
	}
    }
}


##############################################################################
#
#  NAME
#	_parseFunctionPrototype()
#
#  SPEC FILE BNF
#	<function-prototype> :== <function-name> "(" <param-list> ")"
#	<param-list> :== [<param-name> ["," <param-name>]* ]
#
#  SETS
#	functionName		-- Name of function currently being processed
#	paramCount		-- The number of parameters for function
#	paramName[i]		-- The name of the i-th parameter
#	paramList[name] 	-- Set of parameter names for function
#				-- ... [] is the parameter index
#
#
##############################################################################
function _parseFunctionPrototype(	protoFields, protoNF, i) {
    protoNF = split($0, protoFields, "[(), \t]*")
    functionName = protoFields[1]

    paramCount = 0
    clearArray(paramList)
    for (i=2; i<protoNF; i++) {
	paramCount++
	paramName[paramCount] = protoFields[i]
	paramList[protoFields[i]] = paramCount
    }
}


##############################################################################
#
#  NAME
#	_parseReturnType()
#
#  DESCRIPTION
#	Parse the return type.  A "void" type implies a procedure or
#	subroutine.  Return type is the <unmapped-declared-type>.
#	The <unmapped-direction> is implied to be "out" and the
#	<unmapped-transfer-type> is implied to be "value".
#
#  SPEC FILE BNF
#	<unmapped-return-type> :== <unmapped-declared-type>
#
#  SETS
#	returnUnmappedType	-- Return type from spec file
#	returnType		-- Converted or mapped return type
#	_parseErrorOccured	-- Flag indicating error in parsing
#
##############################################################################
function _parseReturnType() {
    returnUnmappedType = $2
    if (! ((returnUnmappedType,"out","value") in typeMap)) {
	#  If returnUnmappedType is not a valid type ...
specError("return type " returnUnmappedType " is not defined in " typeMapFile)
	_parseErrorOccured = true
    } else {
	returnType = typeMapDeclaredType[returnUnmappedType, "out", "value"]
    }
}


##############################################################################
#
#  NAME
#	_parseParamPropBody()
#
#  SPEC FILE BNF
#	<param-prop-body> :== <param-name> <blank> <unmapped-param-type>
#				[<blank> <length-descriptor>]
#				[<param-options-list>]
#	<unmapped-param-type> :== <unmapped-declared-type> <blank>
#				<unmapped-direction> <blank>
#				<unmapped-transfer-type>
#	<unmapped-declared-type> :== <type-name>
#	<unmapped-direction> :== "in" | "out" | "in/out"
#	<unmapped-transfer-type> :== "array" | "reference" | "value"
#	<length-descriptor> :== "[" <index-expr> ["," <index-expr> ]* "]"
#	<index-expr> :== <integer> | <param-name> |
#			["("] <index-expr> <operator> <index-expr> [")"]
#	<operator> :== "+" | "-" | "*" | "/"
#	<param-options-list> :== (<blank> <list-prop-value>)*
#
#  SETS
#	paramUnmappedDeclaredType[name]
#				-- Parameter type from spec file
#	paramUnmappedDirection[name]
#				-- Parameter direction [in,out,in/out] from
#				-- ... spec file
#	paramUnmappedTransferType[name]
#				-- Parameter transfer type
#				-- ... [value, reference, array] from spec file
#	paramDeclaredType[name] -- Parameter type from spec file
#	paramDirection[name]	-- Parameter direction [in,out,in/out] from
#				-- ... spec file
#	paramTransferType[name]	-- Parameter transfer type
#				-- ... [value, reference, array] from spec file
#	paramDimensions[name]	-- The number dimensions of the array/length
#				-- ... 0 if no array/length descriptor
#	paramSubscripts[name,i] -- The size/value of the i-th dimension
#	paramOptions[name]	-- Space separated list of parameter options
#	paramOptions[name,option]
#				-- Set of options for parameter
#	_parseErrorOccured	-- Flag indicating error in parsing
#	
##############################################################################
function _parseParamPropBody(	name,tmpLengthDesc,tmpSubscripts,i,operand,operands,processedLengthDesc) {
    name = $2
    if (! (name in paramList)) {
        specError("param " name " not in function prototype for " functionName)
        _parseErrorOccured = true
    }

    if (! (($3,$4,$5) in typeMap)) {    # Is the type mapped?
        specError($3 " " $4 " " $5 " is not defined in " typeMapFile)
        _parseErrorOccured = true
    }
    paramUnmappedDeclaredType[name] = $3
    paramUnmappedDirection[name] =    $4
    paramUnmappedTransferType[name] = $5

    paramDeclaredType[name] = typeMapDeclaredType[$3, $4, $5]
    paramDirection[name] =    typeMapDirection[$3, $4, $5]
    paramTransferType[name] = typeMapTransferType[$3, $4, $5]

    #
    #	If the parameter has a length/array descriptor 
    #   Break it up into the following variables:
    #
    #
    paramDimensions[name] = 0
    if ($6 ~ /^\[.*\]$/) {
        tmpLengthDesc = $6
        gsub(/[\[\]]/, "", tmpLengthDesc)
        paramDimensions[name] = split(tmpLengthDesc, tmpSubscripts, ",")
	for (i=1; i <= paramDimensions[name]; i++) {
	    if (tmpSubscripts[i] != "") {
		paramSubscripts[name,i] = tmpSubscripts[i]
		if (match(tmpSubscripts[i],/MAX/)) {
    paramSubscripts[name,i] = paramSubscripts[name,i] "," tmpSubscripts[i+1]
		    i++
		    paramDimensions[name]--
		}
	    } else {
		specError("subscript " i " is unspecified")
		_parseErrorOccured = true
	    }
	}

	#
	#   Check operands in subscripts to make sure they are legal
	#
        operands = $6
        gsub(/[-+\/*(),\[\]]/, " ", operands)	# remove all but operands
        split(operands, operand)

        for (i in operand) {
	    # Not an arg or a number 
	    if (!(operand[i] in paramList) && !isConstant(operand[i]))
	    if (operand[i] != "MAX" && operand[i] != "COMPSIZE") {
	        # allow MAX and COMPSIZE keywords
                specError("subscript size operand " operand[i] " is not a parameter")
		_parseErrorOccured = true

            }
        }
	processedLengthDesc = true
    } else {
	processedLengthDesc = false
    }

    #
    #   Process any parameter options if there are any
    #
    if (!processedLengthDesc && NF > 5) {
	i = 6				# If no len descr, start at field 6
    } else if (processedLengthDesc && NF > 6) {
	i = 7				# If len descr, start at field 7
    } else {
	i = NF + 1			# No parameter options
    }

    for (; i <= NF; i++) {
	if (("param",$i) in validPropListValues) {
	    paramOptions[name,$i]
	    paramOptions[name] = paramOptions[name] $i " "
	} else {
	    specError("unknown prop 'param' value: " $i)
	}
    }
}

# ---- mott begin changes

##############################################################################
#
#  NAME
#	_severityIsValid()
#
#  SPEC FILE BNF
#	<err-severity> :== else ("WARNING" | "ERROR" | "FATAL")
#
#  SETS
#	_parseErrorOccured	-- Flag indicating error in parsing
#
#  AUTHOR
#	David Mott
#
##############################################################################
function _severityIsValid()
{
    _num = NF
    severity = $NF
    if (_num == 1) {
	specError("empty reqstates list")
	_parseErrorOccured = true
    }
    else if ((severity != "WARNING") &&
             (severity != "ERROR") &&
             (severity != "FATAL")) {
        specError("unknown reqstate severity '" $_num "'")
        _parseErrorOccured = true
    }
    else {
        _num--
        if ($_num != "else") {
            specError("reqstate missing keyword 'else' before '" $NF "'")
            _parseErrorOccured = true
        }
    }

    return (_parseErrorOccured != true)
}

##############################################################################
#
#  NAME
#	_parseMetaReqStateValue(value, severity)
#
#  DESCRIPTION
#	Add value to either the statesMustNotBeIn list, or the statesMustBeIn
#	list, depending whether value is preceded by '!' or not.
#	Value will only be added to one of these lists if there is no error.
#	value, severity is added to the reqstatesSeverity array.
#	
#	NOTE: ^ is the complement operator. e.g., ^rgbMode means that
#	GL cannot be in RGB mode.
#
#  SPEC FILE BNF
#	<meta-req-value> :== <blank> ["!" | "^"] ("all" | <prop-value>)
#	<err-severity> :== ("WARNING" | "ERROR" | "FATAL")
#
#  SETS
#	statesMustBeIn		-- Comma separated list of states GL must
#				-- ... be in to call this function
#	statesMustNotBeIn	-- Comma separated list of states GL must
#				-- ... NOT be in to call this function
#	reqstatesSeverity[]	-- Array of severity levels for each state
#
#  EXAMPLE
#	Here is an example:
#		reqstates	windowOpen ^rgbMode ^pickMode
#	this means a window must be open, and we cannot be in either
#	RGB or pick mode.
#	this sets:
#		statesMustBeIn = ",windowOpen"
#		statesMustNotBeIn = ",rgbMode,pickMode"
#
#	Another example:
#		reqstates	all !bgnEndMode
#	this means GL must be in all states listed in the top of gl.spec,
#	except bgnEnd mode. It CAN be in bgnEnd mode, it's just not required.
#	this sets:
#		statesMustBeIn = ",depthBufferMode,...,projectionMatrixMode"
#		statesMustNotBeIn = ""
#
#  AUTHOR
#	David Mott
#
##############################################################################
function _parseMetaReqStateValue(value, severity)
{
    name = "reqstates"

    #
    # NOTE: ^all is not allowed, although !all is allowed.
    #
    if (value ~ /^\^/) {	# if complement ^, add to NotBeIn list
	gsub(/^\^/, "", value)	# remove complement mark ^
	if ((name,value) in validPropListValues) {
	    statesMustNotBeIn = statesMustNotBeIn "," value
            reqstatesSeverity[value] = severity
	    severityCountReqstates[severity] += 1
	}
	else return(false)	# propagate error up one level
    }
    else if (value ~ /^!/) {	# if negation, remove from BeIn list
	gsub(/^!/, "", value)	# remove negation mark (!)
	if (value == "all") {
	    statesMustBeIn = ""
	    nf = split(validPropList[name], reqlist, ",")
	    for (i = 2; i <= nf; i++)
                reqstatesSeverity[reqlist[i]] = ""
	    severityCountReqstates[severity] = ""
	}
	else if ((name,value) in validPropListValues) {
	    gsub("," value, "", statesMustBeIn)   # remove ",value" from list
            reqstatesSeverity[value] = ""
	}
	else return(false)	# propagate error up one level

    } else {			# if not negation, add to list
	if (value == "all") {
	    statesMustBeIn = validPropList[name]
	    nf = split(validPropList[name], reqlist, ",")
	    for (i = 2; i <= nf; i++)
                reqstatesSeverity[reqlist[i]] = severity
	    severityCountReqstates[severity] = nf - 1
	}
	else if ((name,value) in validPropListValues) {
	    statesMustBeIn = statesMustBeIn "," value
            reqstatesSeverity[value] = severity
	    severityCountReqstates[severity] += 1
	}
	else return(false)	# propagate error up one level
    }

    return(true)
}

##############################################################################
#
#  NAME
#	_parseReqStates()
#
#  SPEC FILE BNF
#	reqstates ::= <prop-indent> <meta-req-value>* <prop-indent> <err-severity>
#	<meta-req-value> :== <blank> ["!" | "^"] ("all" | <prop-value>)
#	<err-severity> :== else ("WARNING" | "ERROR" | "FATAL")
#
#  SETS
#	statesMustBeIn		-- Comma separated list of states GL must
#				-- ... be in to call this function
#	statesMustNotBeIn	-- Comma separated list of states GL must
#				-- ... NOT be in to call this function
#	reqstatesSeverity[]	-- Array of severity levels for each state
#	_parseErrorOccured	-- Flag indicating error in parsing
#
#  AUTHOR
#	David Mott
#
##############################################################################
function _parseReqStates()
{
    if (_severityIsValid()) {
        # get those properties!
        for (ii = 2; ii <= (NF - 2); ii++) {
            if (!_parseMetaReqStateValue($ii, $NF)) {
                specError("unknown reqstate : " $ii)
                _parseErrorOccured = true
            }
        }
	# make sure no state is in both lists
	if ((statesMustBeIn != "") && (statesMustNotBeIn != "")) {
	    nf = split(statesMustNotBeIn, notlist, ",")
	    for (ii = 2; ii <= nf; ii++) {
	        if (index(statesMustBeIn, notlist[ii]) != 0) {
                    specError(notlist[ii] " and NOT(" notlist[ii] ") are both required")
                    _parseErrorOccured = true
	        }
	    }
	}
    }
}

##############################################################################
#
#  NAME
#	_parseMetaCheckParamValue(value, severity)
#
#  DESCRIPTION
#	If value is 'range', fill in the bound and range globals.
#	
#  SPEC FILE BNF
#	<meta-param-value> :== <blank> (<param-range>|<param-oneof>|<prop-value>)
#	<param-range> :== range ("[" | "(") <number> "," ("]" | ")")
#	<param-oneof> :== oneof "(" <set-member> <more-set-members> ")"
#	<more-set-members> :== "," <set-member>
#	<err-severity> :== else ("WARNING" | "ERROR" | "FATAL")
#
#  SETS
#	checkparamSeverity[]	-- Array of severity levels for each param,
#				-- ... prop-value pair.
#	paramLowerBoundValue[]	-- Lower bounds value of each param.
#	paramLowerBoundRange[]	-- Lower range, either "inclusive" or "exclusive"
#	paramUpperBoundValue[]	-- Upper bounds value of each param.
#	paramUpperBoundRange[]	-- Upper range, either "inclusive" or "exclusive"
#				-- ... for the above, "" means no bound.
#	checkparamSetSize[]	-- Array of severity levels for each state
#	checkparamOneOfSet[]	-- Param must be equal to one of this set
#	_parseErrorOccured	-- Flag indicating error in parsing
#
#  AUTHOR
#	David Mott
#
##############################################################################
function _parseRange(paramname, value)
{
    # lower bound range
    _range = substr(value, 6, 1)  # 6 is the position of the char after 'range'
    if (_range == "[")
	paramLowerBoundRange[paramname] = "inclusive"
    else if (_range == "(")
	paramLowerBoundRange[paramname] = "exclusive"
    else return (false)

    # lower bound value
    comma_pos = index(value, ",")
    len = comma_pos - 7  # 7 is the char after 'range(' or 'range['
    if (len == 0)
	paramLowerBoundValue[paramname] = ""  # no lower bound
    else
        paramLowerBoundValue[paramname] = substr(value, 7, len)

    # upper bound range
    lastchar_pos = length(value)
    _range = substr(value, lastchar_pos, 1)   # last char is either ']' or ')'
    if (_range == "]")
	paramUpperBoundRange[paramname] = "inclusive"
    else if (_range == ")")
	paramUpperBoundRange[paramname] = "exclusive"
    else return (false)

    # upper bound value
    len = lastchar_pos - (comma_pos + 1)
    if (len == 0)
	paramUpperBoundValue[paramname] = ""  # no upper bound
    else
        paramUpperBoundValue[paramname] = substr(value, (comma_pos + 1), len)

    return (true)
}

##############################################################################
#
#  NAME
#	_parseOneOf()
#
#  SPEC FILE BNF
#	<param-oneof> :== oneof "(" <set-member> <more-set-members> ")"
#	<more-set-members> :== "," <set-member>
#
#  SETS
#	checkparamSetSize[]	-- Array of severity levels for each state
#	checkparamOneOfSet[]	-- Param must be equal to one of this set
#
#  AUTHOR
#	David Mott
#
##############################################################################
function _parseOneOf(paramname, value)
{
    # get set members
    _startset = 6   # 6 is the char position just after 'oneof'
    _endset = length(value)

    # make sure the syntax is correct: oneof(...)
    _setparen = substr(value, _startset, 1)
    if (_setparen != "(")
	return (false)
    _setparen = substr(value, _endset, 1)
    if (_setparen != ")")
	return (false)

    # grab that set!
    len = _endset - (_startset + 1)
    if (len == 0)
	return (false)
    else {
        _set = substr(value, (_startset + 1), len)
	checkparamSetSize[paramname] = split(_set, _tempArray, ",")
	for (jj = 1; jj <= checkparamSetSize[paramname]; jj++) {
	    checkparamOneOfSet[paramname, jj] = _tempArray[jj]
        }
    }

    return (true)
}

##############################################################################
#
#  NAME
#	_parseMetaCheckParamValue()
#
#  SPEC FILE BNF
#	<meta-param-value> :== <blank> (<param-range>|<param-oneof>|<prop-value>)
#	<param-range> :== range ("[" | "(") <number> "," ("]" | ")")
#
#  SETS
#	checkparamSeverity[]	-- Array of severity levels for each param,
#				-- ... prop-value pair.
#	paramLowerBoundValue[]	-- Lower bounds value of each param.
#	paramLowerBoundRange[]	-- Lower range, either "inclusive" or "exclusive"
#	paramUpperBoundValue[]	-- Upper bounds value of each param.
#	paramUpperBoundRange[]	-- Upper range, either "inclusive" or "exclusive"
#				-- ... for the above, "" means no bound.
#	checkparamSetSize[]	-- Array of severity levels for each state
#	checkparamOneOfSet[]	-- Param must be equal to one of this set
#	checkparamProps[]	-- All the props for this param. range[...)
#				-- ... is written "range", oneof(...) is "oneof"
#
#  AUTHOR
#	David Mott
#
##############################################################################
function _parseMetaCheckParamValue(paramname, value, severity)
{
    name = "checkparam"

    if (value ~ /^range/) {
	if (_parseRange(paramname, value)) {
            checkparamSeverity[paramname, "range"] = severity
	    checkparamProps[paramname] = checkparamProps[paramname] "," "range"
	    severityCountCheckparam[severity] += 1
	}
	else return (false)	# propagate error up one level
    }
    else if (value ~ /^oneof/) {
	if (_parseOneOf(paramname, value)) {
            checkparamSeverity[paramname, "oneof"] = severity
	    checkparamProps[paramname] = checkparamProps[paramname] "," "oneof"
	    severityCountCheckparam[severity] += 1
	}
	else return (false)	# propagate error up one level
    }
    else if ((name,value) in validPropListValues) {
        checkparamSeverity[paramname, value] = severity
	checkparamProps[paramname] = checkparamProps[paramname] "," value
	severityCountCheckparam[severity] += 1
    }
    else return(false)	# propagate error up one level

    return(true)
}

##############################################################################
#
#  NAME
#	_parseCheckParam()
#
#  SPEC FILE BNF
#	checkparam ::= <prop-indent> <param-name> <checkparam-body>
#	<checkparam-body> :== <meta-param-value>* <blank> <err-severity>
#	<meta-param-value> :== <blank> (<param-range>|<param-oneof>|<prop-value>)
#	<param-range> :== range ("[" | "(") <number> "," ("]" | ")")
#	<param-oneof> :== oneof "(" <set-member> <more-set-members> ")"
#	<more-set-members> :== "," <set-member>
#	<err-severity> :== else ("WARNING" | "ERROR" | "FATAL")
#
#  SETS
#	checkparamSeverity[]	-- Array of severity levels for each param,
#				-- ... prop-value pair.
#	paramLowerBoundValue[]	-- Lower bounds value of each param.
#	paramLowerBoundRange[]	-- Lower range, either "inclusive" or "exclusive"
#	paramUpperBoundValue[]	-- Upper bounds value of each param.
#	paramUpperBoundRange[]	-- Upper range, either "inclusive" or "exclusive"
#				-- ... for the above, "" means no bound.
#	checkparamSetSize[]	-- Array of severity levels for each state
#	checkparamOneOfSet[]	-- Param must be equal to one of this set
#	_parseErrorOccured	-- Flag indicating error in parsing
#
#  NOTES
#	Here is an example:
#		checkparam x range[0.0,1.0) else ERROR
#	this means 0.0 <= x < 1.0
#	this sets:
#		paramLowerBoundValue["x"] = 0.0
#		paramLowerBoundRange["x"] = "inclusive"
#		paramUpperBoundValue["x"] = 1.0
#		paramUpperBoundRange["x"] = "exclusive"
#
#	Another example:
#		checkparam y oneof(MSINGLE,MVIEWING,MPROJECTION) else ERROR
#	this means y must be one of the members of the set listed.
#	this sets:
#		checkparamSetSize["y"] = 3
#		checkparamOneOfSet["y", 1] = "MSINGLE"
#		checkparamOneOfSet["y", 2] = "MVIEWING"
#		checkparamOneOfSet["y", 3] = "MPROJECTION"
#
#	One more example:
#		checkparam z nonnull nonsingular
#	these properties are not checked for explicitly, so they had better
#	be members of the valid props for checkparam at the top of gl.spec.
#
#  AUTHOR
#	David Mott
#
##############################################################################
function _parseCheckParam()
{
    if (_severityIsValid()) {
	# make sure the param we are checking exists for this function
        if (! ($2 in paramList)) {
            specError("param " $2 " not in function prototype for " functionName)
            _parseErrorOccured = true
        }

        # get those properties!
        for (i = 3; i <= (NF - 2); i++) {
            if (!_parseMetaCheckParamValue($2, $i, $NF)) {
                specError("unknown checkparam property : " $i)
                _parseErrorOccured = true
            }
        }
    }
}

# ---- mott end changes


##############################################################################
#
#  NAME
#	_parseProp()
#
#  SPEC FILE BNF
#	<prop-line> ::= <prop-indent> <prop-name> <meta-prop-value>*
#	<meta-prop-value> :== <blank> ["!"] ("all" | <prop-value>)
#
#  SETS
#	propList[propname]	-- Set of properties for this function
#				-- ... [] is a comma separated list of
#				-- ... prop values
#	_parseErrorOccured	-- Flag indicating error in parsing
#
##############################################################################
function _parseProp(	i) {

    # mott - begin additions for gldebug
    if ($1 == "checkparam")
	_parseCheckParam()
    else if ($1 == "reqstates")
	_parseReqStates()
    # mott - end

    else if ($1 in validPropList) {		# if its a valid prop
	propList[$1]				# create it for this function
	for (i=2; i<=NF; i++) {
	    if (!_parseMetaPropValue($1, $i)) {
		specError("unknown prop '" $1 "' value: " $i)
		_parseErrorOccured = true
	    }
	}
    } else {
	specError("unknown prop '" $1 "'")
	_parseErrorOccured = true
    }
}


##############################################################################
#
#  NAME
#	_parseMetaPropValue(name, value)
#
#  DESCRIPTION
#	Add name and value to propList array if name is a valid property
#	If value is equal to all, all of the values from validPropList[]
#	are added to propListValues.  If the value begins with an exclamation
#	point (!), the name,value pair is deleted from the propListValues.
#	This ! negation permits "all but 'value'" short-hand notation.
#
#  SPEC FILE BNF
#	<meta-prop-value> :== <blank> ["!"] ("all" | <prop-value>)
#
#  SETS
#	propList[propname]	-- Set of properties for this function
#				-- ... [] is a comma separated list of
#				-- ... prop values
#	propListValues[propname,value]
#				-- Set of (propname,values) for this function
#
#
##############################################################################
function _parseMetaPropValue(name, value,	i, nf, values) {
    if (value ~ /^!/) {		# if negation, remove from list
	gsub(/^!/, "", value)	# remove negation mark (!)
	if (value == "all") {
	    nf = split(validPropList[name], values, ",")
	    for (i=2; i<=nf; i++) {
		delete propListValues[name,values[i]]
		gsub("," values[i], "", propList[name])
	    }
	} else if ((name,value) in validPropListValues) {
	    delete propListValues[name,value]
	    gsub("," value, "", propList[name])
	} else if ((name,"*") in validPropListValues) {
	    delete propListValues[name,value]
	    gsub("," value, "", propList[name])
	} else {
	    return(false)	# propagate error up one level
	}
    } else {			# if not negation, add to list
	if (value == "all") {
	    propList[name] = propList[name] validPropList[name]
	    nf = split(validPropList[name], values, ",")
	    for (i=2; i<=nf; i++) {
		propListValues[name,values[i]]
	    }
	} else if ((name,value) in validPropListValues) {
	    propListValues[name,value]
	    propList[name] = propList[name] "," value
	} else if ((name,"*") in validPropListValues) {
	    propListValues[name,value]
	    propList[name] = propList[name] "," value
	} else {
	    return(false)	# propagate error up one level
	}
    }
    return(true)
}


##############################################################################
#
#  NAME
#	_parsingErrors()
#
#  DESCRIPTION
#	Check for parsing errors;
#	
##############################################################################
function _parsingErrors(		i) {
    if (_parsedPrototype) {
	if (! _parsedReturn) {
	    specError("return type never _parsed for " functionName)
	    _parseErrorOccured = true
	}
	for (i in _unparsedRequiredProps) {
	    specError("required prop '" i "' never _parsed for " functionName)
	    _parseErrorOccured = true
	}
	if (_parseErrorOccured) {
	    return true
	} else {
	    return false
	}
    } else {
	return true
    }
}

##############################################################################
#
#  NAME
#	_resetParseStates()
#
#  DESCRIPTION
#	Reset the parsing States to false.  The parsing routines will
#	indicate errors or successful completion by setting the appropriate
#	parsing flag(s) to true.
#
##############################################################################
function _resetParseStates() {
    _parseErrorOccured = false
    _parsedPrototype = false
    _parsedReturn = false
}


##############################################################################
#
#  NAME
#	clearArray(array)
#
#  DESCRIPTION
#	Removes all values from the specified array.
#
##############################################################################
function clearArray(array,	i) {
    for (i in array) {
	delete array[i]
    }
}


##############################################################################
#
#  NAME
#	inParamOptions(name,option) : returns true/false value
#
##############################################################################
function inParamOptions(name, option) {
    return (name, option) in paramOptions
}


##############################################################################
#
#  NAME
#	isConstant(string): returns true/false value
#
#  DESCRIPTION
#	Returns true if argument is a constant (decimal) value and is not
#	an identifier.
#
##############################################################################
function isConstant(string) {
    if (string ~ /^[0-9]+$/) {
	return(true)
    } else {
	return(false)
    }
}


# END Parsing functions

##############################################################################
#
#  Wire Functions
#
##############################################################################


##############################################################################
#
#  NAME
#	_readWireFile()
#
#  DESCRIPTION
#	Create the wire map by reading the specified wire file.  The
#	format of the file is simple: 2 columns, left column is the
#	DeclaredType of the parameter,the right column is the wire
#	format for the parameter.
#
##############################################################################
function _readWireFile(	) {
    WireFile = typeMapPath "/gl.wire"
    while (stripcomments WireFile | getline) {
	wiretype[$1] = $2
    }
    close(WireFile)
}

# END Wire functions


##############################################################################
#
#  Type Map Functions
#
##############################################################################


##############################################################################
#
#  NAME
#	_readTypeMap(typeMapFile)
#
#  DESCRIPTION
#	Create the type map by reading the specified typeMapFile
#	invoking the _makeTypeMap() function.
#
#	The type map uses a contextual wildcard character "*" for
#	short-hand description of type maps.  The expansion of "*"
#	is as follows:
#
#		Field			"*" Wildcard Expansion
#		====================	====================================
#		unmapped-direction 	All directions (in, out, in/out)
#		unmapped-transfer-type 	All transfer-types (array, reference,
#					... and value)
#		mapped-direction	Corresponding unmapped-direction
#		mapped-transfer-type	Corresponding unmapped-transfer-type
#
#  TYPE MAP FILE BNF
#	<type-map-file> ::= <type-map-line>*
#	<type-map-line> :== [<type-map>] [<comment>]
#	<type-map> :== <unmapped-type> "," <mapped-type>
#	<meta-unmapped-type> :== <unmapped-declared-type> ","
#			<meta-unmapped-direction> ","
#			<meta-unmapped-transfer-type>
#	<unmapped-declared-type> :== <type-name>
#	<meta-unmapped-direction> :== <direction> | "*"
#	<meta-unmapped-transfer-type> :== <transfer-type> | "*"
#	<meta-mapped-type> :== <meta-mapped-declared-type> ","
#			<meta-mapped-direction> ","
#			<meta-mapped-transfer-type>
#	<meta-mapped-declared-type> :== <type-name>
#	<meta-mapped-direction> :== <direction> | "*"
#	<meta-mapped-transfer-type> :== <transfer-type> | "*"
#	<direction> :== "in" | "out" | "in/out"
#	<transfer-type> :== "array" | "reference" | "value"
#	
##############################################################################
function _readTypeMap(typeMapFile,	d,t,OLDFS) {
    #
    #	Build type map from short hand
    #

    OLDFS = FS
    FS = "[ \t]*,[ \t]*"	# Map table uses comma separators
    if (typeMapFile == "") {
	readError("/usr/lib/libspec.awk", "no typeMapFile was specified in _readTypeMap()")
	exit 1
    }
    while (stripcomments typeMapFile | getline) {
	if ($2 == "*") {
	    for (d in validDirections) {
		if ($3 == "*") {
		    for (t in validTransferTypes) {
			_makeTypeMap($1, d, t, $4, $5, $6)
		    }
		} else if ($3 in validTransferTypes) {
		    _makeTypeMap($1, d, $3, $4, $5, $6)
		} else {
		    readError(typeMapFile, "unknown transfer type: " $5)
		}
	    }
	} else if ($2 in validDirections) {
	    if ($3 == "*") {
	        for (t in validTransferTypes) {
	 	    _makeTypeMap($1, $2, t, $4, $5, $6)
		}
	    } else if ($3 in validTransferTypes) {
		_makeTypeMap($1, $2, $3, $4, $5, $6)
	    } else {
		readError(typeMapFile, "unknown transfer type: " $5)
	    }
	} else {
	    readError(typeMapFile, "unknown transfer type: " $5)
	}
    }
    FS = OLDFS			# Restore to use white space for spec
    close(typeMapFile)
}


##############################################################################
#
#  NAME
#	_makeTypeMap(type, direction, transfer, maptype, mapdir, maptrans)
#
#  SETS
#	typeMap[type,direction,transfer]
#				-- Set of raw spec file types which are mapped
#	typeMapDeclaredType[type,direction,transfer]
#				-- Mapped declared type indexed by raw types
#	typeMapDirection[type,direction,transfer]
#				-- Mapped direction indexed by raw types
#	typeMapTransferType[type,direction,transfer]
#				-- Mapped transfer type indexed by raw types
##############################################################################
function _makeTypeMap(type, direction, transfer, maptype, mapdir, maptrans) {
    typeMap[type,direction,transfer]

    if (maptype == "*") {
        typeMapDeclaredType[type,direction,transfer] = type
    } else {
        typeMapDeclaredType[type,direction,transfer] = maptype
    }

    if (mapdir == "*") {
        typeMapDirection[type,direction,transfer] = direction
    } else if (mapdir in validDirections) {
        typeMapDirection[type,direction,transfer] = mapdir
    } else {
        error("unknown direction: " mapdir)
    }

    if (maptrans == "*") {
        typeMapTransferType[type,direction,transfer] = transfer
    } else if (maptrans in validTransferTypes) {
        typeMapTransferType[type,direction,transfer] = maptrans
    } else {
        error("unknown transfer type: " maptrans)
    }
}


##############################################################################
#
#  NAME
#	_dumpTypeMap()
#
#  DESCRIPTION
#	Diagnostic/debugging function for printing the type map to stderr.
#
##############################################################################
function _dumpTypeMap(	i) {
    print "\nDump of type Map" | stderr
    printf "%-32s -> %s\n", "***** Input Type *****", \
		"***** Output Type *****" | stderr
    for(i in typeMapDeclaredType) {
	split(i, foo, SUBSEP)
	printf "%-32s", foo[1] " " foo[2] " " foo[3] | stderr
	print typeMapDeclaredType[i], typeMapDirection[i], \
		typeMapTransferType[i] | stderr
    }
    print "" | stderr
}

# END Type Map functions

##############################################################################
#
#	Error message routines
#
##############################################################################

##############################################################################
#
#  NAME
#	specError(message)
#
#  DECRIPTION
#	Print an error message for the spec file being read.
#
##############################################################################
function specError(message) {
    readError(FILENAME, FNR, message)
}

##############################################################################
#
#  NAME
#	readError(message)
#	readError(filename, message)
#	readError(filename, linenumber, message)
#
#  DESCRIPTION
#	Print a read error message for the file/linenumber specified.
#
##############################################################################
function readError(arg1, arg2, arg3) {
    if (arg2 == "") {
	error(arg1)
	return
    }
    if (arg3 == "") {
	error("file " arg1 ": " arg2)
	return
    }
    error("file " arg1 ", line " arg2 ": " arg3)
}

##############################################################################
#
#  NAME
#	error(message)
#
#  DESCRIPTION
#	Print an error message.
#
##############################################################################
function error(message) {
    print "ERROR: " message "." | stderr
    if ($0 != "") {
	print ">>>>" $0 "<<<<"| stderr
    } else {
	print ">>>> CHECK LINES ABOVE LINE INDICATED <<<<"| stderr
    }
}

# END Error routines