NIDR Extensions

Here is a brief account of facilities added to nidrgen
after SAND2008-2261P ("Specifying and Reading Program Input with NIDR",
http://www.sandia.gov/~dmgay/nidr08.pdf) was written.
The facilities are meant to simplify preparation and maintenance
of an updated Jaguar (a GUI for DAKOTA).

New possible items in the input .spec file:

	>  num
	>= num
	<= num
	<  num

specify bounds on numerical entities (INTEGER, INTEGERLIST,
REAL, REALLIST).

	:= value
	:= defname value

specifies a default value (string-valued for STRING and STRINGLIST,
numeric for INTEGER, INTEGERLIST, REAL, REALLIST); if defname is
present, it must be of a form acceptable as a C-preprocessor name
(i.e., starting with an upper or lower case letter, followed by
a possibly empty string of letters, digits and underscores).
With suitable nidrgen invocations (described below), the collection
of defnames is turned into a header file of #define lines, so
the defnames can be used in the DAKOTA source to provide initial
values that are automatically in sync with the .nspec file
(and which the GUI can show).

The following new items are included in a variant of NIDR_keywds.H,
tentatively called $DAKOTA/src/NIDR_guikeywds.h, that has extra
information for GUIs.

	DESC string

provides a description of the associated keyword, perhaps
including a URL for more detailed discussion.

	GROUP string

provides details about screen layout and possibly a
"screen name" for the associated keyword.

	LEN keyname

indicates an INTEGER-valued keyword whose value specifies
the length of the present keyword, which should be of type
INTEGERLIST, REALLIST, or STRINGLIST.

	TAG string

provides a way to connect this keyword with further entries
for it (typically GROUP, LEN, and DESC) taken from a second
input file (tentative called $DAKOTA/src/dakota.input.desc).
Such entries begin with the same "TAG string".

Two new fields appear in NIDR_keywds.H:  REAL-valued lower
and upper bounds for INTEGER, INTEGERLIST, REAL, and REALLIST
keywords (if specified with the <, <=, >=, and/or > operators
above).  New bits in the "kind" field indicate whether bounds
are present and whether they are strict.

The GUI variant NIDR_guikeywds.h omits function details
(pointers to functions that the NIDR parser calls when DAKOTA
runs) and adds a keyword number, initial values (numeric and
string, the relevant one depending on the keyword's type),
and the GROUP and DESC strings.

Strings are delimited by " characters.  A "string" value
can be broken into several adjacent quoted strings
(separated by white space, including newlines), which are
concatenated, as in C or C++ source files.  For example,

	"This is an"
	" example of strings"
	" to be concatenated."

is treated the same as

	"This is an example of strings to be concatenated."

When invoked with any of

	nidrgen -?
	nidrgen -h
	nidrgen --help

the parser-generator nidrgen explains its usage.  For example,

	nidrgen foo.spec foo.desc outdefs.h outkeywds.h

reads the first two files and writes the second two
(with outdefs.h containing #define lines and outkeywds.h
corresponding to $DAKOTA/src/NIDR_keywds.H).  For another example,

	nidrgen -g foo.spec foo.desc >guikeywds.h

writes the GUI variant of the keyword header (called NIDR_guikeywds.h
above).  For more examples, see the makefile.

As a possible convenience, for keywords that have a TAG but not
a GROUP specification, the TAG is supplied as GROUP in
NIDR_guikeywds.h (unless nidrgen is invoked with -G to suppress
this behavior).

-- David M. Gay, 16 Dec. 2008

======= More additions (April 2010) =======

The NIDR parser-generator (nidrgen) now accepts

	DYNLIB "mylib.dll"

as an alternative to {...} in the *.nspec file.  This causes shared
library mylib.dll to be opened (by dlopen() under Linux); the library
must provide function keyword_add() returning a pointer to a KeyWord
structure that provides details, including "start" and "final"
routines and contained keywords, for the loading keyword, i.e., the
keyword whose specification mentions DYNLIB.  If file inputspec
describes the keywords to be conveyed in mylib.dll (with the loading
keyword as top-level keyword, having a value of the same kind as the
loading keyword), then

	nidrgen -l inputspec

generates source for keyword_add().

Also new the ability of nidrgen to read shared libraries built
from source generated by previous runs of "nidrgen -l ...".
Assocaited new command-line options to nidrgen (as seen in the
output from "nidrgen -?" or "nidrgen --help") are:

-k keyname	{ library mode with input containing several keywords
		  to be contained in keyword keyname; implies -l and
		  has no other effect if -D, -g, -j, -p, or -s is given.
		  If -l is given without -k and several keywords appear
		  in the input, assume "-k KeywordTop". }
-L libname	{ obtain keyword details from library libname (compiled
		  from source produced by an earlier "nidrgen -l ..."
		  invocation); non-option arguments in this case are
		  [defs_out [keywds_out]] }
-l		{ library mode: with -D, -g, -j, -p, or -s, attempt to
		  load libraries specified with "DYNLIB libname" and
		  incorporate keyword specifications provided by the
		  loaded libraries; otherwise generate source for
		  compilation into a shared library for loading when a
		  keyword marked with "DYNLIB libname" (in a separate
		  run of nidrgen) is seen.  The library provides
		  contained keywords and any needed final routine for
		  the marked keyword. }

On my Linux box, after

  nidrgen -lfn- -h nidr.h dakota.input.nspec dakota.input.desc >zap2.c
  gcc -fPIC -shared -o zap2.dll zap2.c

all of

	nidrgen -efp -L zap2.dll
	nidrgen -efpLzap2.dll
	nidrgen -efpL zap2.dll
	nidrgen -efp dakota.input.nspec

give the same output, as do all of

	nidrgen -egG dakota.input.nspec dakota.input.desc
	nidrgen -egG -L zap2.dll
	nidrgen -egGL zap2.dll
	nidrgen -egGLzap2.dll

and both of

	nidrgen -ftn- dakota.input.nspec dakota.input.desc
	nidrgen -ftn- -Lzap2.dll

Moreover,

	nidrgen -Lzap2.dll zap3 zap4
	nidrgen -L zap2.dll zap3 zap4
	nidrgen dakota.input.nspec dakota.input.desc zap3 zap4

all give the same files zap3 and zap4 (known in $DAKOTA/src as
NIDR_initdefs.h and NIDR_keywds.H), and

	nidrgen -j specsum dakota.input.nspec
	nidrgen -j specsum -Lzap2.dll
	nidrgen -L zap2.dll -j specsum

all give the same specsum file.

File dylib_test.zip ($DAKOTA/packages/nidr/dylib_test.zip)
provides a little test of the new DYNLIB facilities:

	unzip dylib_test
	cd dylib_test
	make
	make clean

File dylib_test/README of dylib_test.zip provides more details.

File dylib_test2.zip has some tests I found useful in debugging.

======= More additions (May 2010) =======

The NIDR parser-generator (nidrgen) now accepts

	LIBNAME

as an alternative to STRING in the *.nspec file.  This causes a string
to be expected in the input; the string should be the name of a shared
library created as above from "nidrgen -l ..." along with suitable
compiling and linking.

File dylib_test3.zip has a simple test of LIBNAME.

-- David M. Gay, 28 May 2010
