![]() |
What qsg is, how it works, command-line options, the scripting language and the library. |
![]() |
Although any arbitrary shell pipeline can be used as a
script generator, the primary ones used are qsg |
![]() |
qsg is several things at once. First and foremost, it is a script generator used to create mimk or make files or shell scripts. Beyond that, qsg is a small programming language that can be used for a variety of applications such as this document, xfig diagrams, the vci interface, and small programming exercises such as Scientific American puzzles and other such problems. Using qsg on simple files is probably the best way to learn it, as in: % cat > tmp if @argvYou can try out the qsg standard library scripts directly from the command shell, as in: % qsg -c hanoi 5 1: move ring 1 from this one to that one 2: move ring 2 from this one to over there 3: move ring 1 from that one to over there 4: move ring 3 from this one to that one ... % qsg -c commands example.c #include mimkvars.qh #include deps.qh #define _Main_ example Objects:V: example.o example.o:P: _S_(example.c) _Touch_(cc) _T_cc -c _F_cc _F_cc[example.c] _F_cc_c _F_cc_c[example.c] \ _Optimize_(example.c) _Threads_(example.c) \ _CcFlags_(example.c) _D_cc _D_cc[example.c] \ _InclFlags_() _A_(example.c) ... ...qsg has a variety of applications. For example, this guide itself is written in qsg using the html.qsl qsg library -- see x-html. It is also used to process the PostScript files to insert page footers. vci, the generalized interface to version control systems, is implemented using qsg libraries, and qmsdev, which generates Microsoft Developer's Studio project files, is yet another qsg variant. However, qsg's primary application is to convert qeffiles' scripts into the input for the back-end such as mimk or qsh. |
||
A Typical qeffile |
Every directory in which a construction occurs must have an associated file called qeffile (or qeffile2). The part of that file that follows the Begin line, is usually a qsg script. Everything that applies to standard qsg scripts applies also to the script portion of a qeffile. The most common qeffile looks something like this: BeginWhen the Begin line does not have arguments, the value of the @DefaultBeginLine is used. If it is not defined, "qsg ![]() The
|
![]() |
The qsg components of the QEF product consist of the following tools and files: |
||||||||||||||||||||||||||
qsg | The general-purpose script generator, with a built-in compiler and interpreter. | ||||||||||||||||||||||||||
lib/qsg/std.qsl | Archive of standard qsg scripts in compiled form. qsg and qsgdump search this library for requested scripts. Additional libraries, such as a project specific library, can be created as required. | ||||||||||||||||||||||||||
lib/qsg/*.qsl |
There are a variety of additional qsg libraries provided in the
<qtree>/lib/qsg directory.
These are:
To get a listing of the scripts provided by a particular library use: % qsgdump -L -llib -l-NThe ![]() % qsgdump -S -llib scriptTo see a script's summary, use ![]() ![]() |
||||||||||||||||||||||||||
qsgcomp | Compiles its argument script and outputs object code. It is used to create object files put into script library. | ||||||||||||||||||||||||||
qsgdump |
Compiles argument scripts (if necessary) or extracts from library and
dump code (by default), summary (![]() ![]() |
||||||||||||||||||||||||||
x-qsg |
An eXplanatory database describing features of the qsg system.
To retrieve a list of the major items in the database use:
% x-qsg x-qsg : qsg and its support library eXplanatory D.B. qsg-intro : introduction to qsg qsg-tools : qsg tools and files qsg-M : that qsg -M flag qsg-variables : variables in qsg argv : arguments to a qsg script <Q>/lib/qsg/std.qsl : the standard qsg library qsg-sfxmaps : qsg mapping of suffix to script controls qsg-scripts : list of standard qsglib scripts qsg-input : qsg input conventions and the @ escape qsg-syntax : qsg keywords and syntax tilde-ops : the qsg postfixTo retrieve the information of a particular item, such as qsg-M, use: % x-qsg qsg-M qsg-M : that qsg -M flag As has been mentioned in qsg-intro, about 50% of the Begin lines are: Begin qsg -M or its equivalent: Begin ...Appendix F: The QEF Specialist's Reference Card contains four items extracted from x-qsg for quick reference. These are:
|
![]() |
The synopsis of the qsg command is: qsg [qsg-options] [--] [script-options]The " ![]() ![]() ![]() % qsg -x qsg [-xVMmqrST] [-C[mp]] [-a file] [-f script]will output a brief description of all the flags and options. Typically, qsg is called with one of the following options:
The qsg The qsg -f <file> option is usually used to run a script that is not contained in a script library, as in: % qsg -f file -- argumentsTypically, you run a script in this fashion until it is thoroughly debugged, at which time you place the script in a library. The qsg -c <command> option is usually used directly from the command line, as in: % qsg -c hanoi 3 # run 3 ring tower of hanoiFor the ![]() ![]() |
||||||||
qvrs variables used by qsg |
qsg scripts can access any qvrs variable or expression using
the functions @(qvrs variable),
@(qvrsexpr expression),
or the short form of the qvrs function, @{variable}.
However, four variables are used by qsg itself.
These are:
|
||||||||
Running a Library Script |
To run a qsg library script, you simply need to know its name and the flags and arguments it accepts. The result of running a library script is almost always another script to another process. That is, scripts are both the input to and output from qsg. Running the qsg script to create a library or program, for example, does not directly create the library or program. Rather, it creates a mimk script to accomplish this. To actually create the program or library, you must interpret the generated script using the appropriate back-end (e.g. mimk). This processing, that is the invocation of qsg to create the script, and mimk to interpret it, is all managed by qef. For a list of the scripts available in the qsg library, use the command: % x-qsg -L \*scripts For a detailed description of any particular script, use the command: % x-qsg <scriptname> |
![]() |
The standard qsg library consists of seventy five scripts designed to handle the most common tasks involved in software production. We recommend that you do not modify any of these scripts, but we encourage you to examine them for useful constructs. To get the source for a specific library module, use: % qsgdump -S script Some of the most important library scripts are described in Chapter 7.5: The Construction Script. A project might need to extend the range of facilities offered by std.qsl to deal with languages and/or file types not currently handled. While you could add new scripts to the standard qsg library, we recommend that you create new a new project or organization specific qsg library instead. This is best done as follows:
|
![]() |
A qsg script has the following structure: summary <flag_spec> [-] <argument_spec> <explanatory text> endsummary # zero or more procs proc <name> <flags> [-] <arguments> ... endproc <script> Both the summary and the procedure definition(s) are optional.
The summary defines the flags and their types accepted by the script.
The summary/endsummary keywords can also
bracket a text description, displayed by qsgdump -X.
The proc keyword begins a procedure.
Procedures are local to the defining script.
The arguments specify the name of the procedure and the flags, if any.
The procedure terminates with endproc.
The [ The actual script consists of keywords, variables, and arguments. Variables are lists of words. A variable's value may be incorporated into an argument list by placing the @ character before it: @L is the value of the variable L. Literal spaces, tabs, and `@'s can be embedded in an argument list by preceding it with an `@'. The @ character can also be used to escape newlines to split long lines. Any list can be modified by a post-fix |
![]() |
The following is a contrived qsg script that contains examples of
some of the syntactic forms of the language, with comments to
explain their use and semantics.
summary [-ab] [-p parm] [-l list]+ [-o[opt]] [-] @ arguments ... short optional description -a a boolean flag -- variable aFlag contains value -b another flag -p parm value assigned to pParm -- only one allowed second instance will raise fatal error This description should include the default. -l list+ values assigned to lParm -- multiple instances allowed -o[opt] optional value -- oOpt
|
![]() |
qsg variables come in three flavours: local, global, and first-time
switches.
Local and global variables are lists of white space separated elements.
An `@' escaped space, tab, or `@' can be used to embed literal
spaces, tabs, or `@'s in a list element,
although they are converted to 037, 035, and 036 respectively.
The encoded forms are converted to the normal form on output.
Local variable names are one of more alphanumerics or underbars, the first of which cannot be a digit (i.e., the same as C modulo the `$' allowed by some C compilers). Global variable names can be any normal printable unsigned ASCII character greater than a space (i.e., bang to tilde), however use of `(' or `)' will make it awkward to retrieve the value using the literal name. First time switch names can also be any sequence of printable characters excluding white space (one can use escaped spaces and tabs if really necessary).
The local variables are local to the current instance of the script or proc.
When a script or proc is invoked,
the flag processing then will set any specified flag's variable.
The simple Global variables are, obviously, global and are accessible to any script or proc, as are first time switches.
Global variables are set or modified using gset, gappend, gpop, and gprepend. The latter two functions are often used to implement stacks. In addition to the keywords, the special expansion @[/List], as in: ... @[/ Example example value]sets the global variable named by first word of the List (e.g., Example) to the balance of the list (e.g., example value). A global variable's value may be retrieved using @(g name) or its alias @(global ...). First-time-switches are used to prevent processes from being done a second time such as the processing for a source file or the output of the include of a header file. A first time switch can be set using the keyword set1st or the test and set function 1stset as in: if @(1stset switch-name) # switch-name was not previously set but it is now # ... first time only code else # 1st time switch was set previously # 2nd and subsequent time code fiA first time switch can be tested without setting it using the function @(notset name) which returns 1 (0) if the 1st time switch name wasn't (was) previously set. |
![]() |
Frequently, as discussed in Section 4, a project can benefit from
having its own qsg scripts to supplement or override those provided
by the standard qsg libraries as listed in Section 2.
The creation and use of such a library is described in
Section 4 and project.qsl(x-qmisc).
This section briefly discusses some of the principles that should be followed in developing new scripts that will conform to the normal style and form of the standard scripts. |
qsg-scripts(x-qsg) | This item lists the standard scripts. It should be reviewed as it is likely that there is an existing script that is similar to the script that you need to create. |
qsl_init |
Your library should have a script called qsl_init.
This script is invoked when your library is loaded.
It is typically used to bind scripts to suffixes, initialize
global variables such as the target keys, etc.
To view the source for the standard library's qsl_init, use:
% qsgdump -S qsl_init |
Summaries |
All scripts should have complete summaries giving the synopsis, a short
description, descriptions of all the flags (including their defaults
if relevant), and supplementary notes.
These summaries can be converted into an x_db database
if desired, but in any case they can be retrieved using:
% qsgdump -X script |
Types of Scripts | The qsg-scripts(x-qsg) item lists the standard scripts, partitioning them into construction, command, make object, and support scripts. When creating new scripts, attempts should be made to make those scripts resemble existing scripts in their interface and purpose. Scripts should use the support scripts as much as possible. The more important support scripts are described briefly below. |
Conventions |
Command scripts should be designed to take multiple argument
files and support much the same ![]() |
cmds_X | Scripts called cmds_X are used to process command *.X files and files with suffixes mapped to it using qsgcmdproc(x-qsg). A prime example of such as script is cmds_xdb which should examined as a prototype. Such scripts should process all its argument files, creating recipes to build all intermediate and installed files and the appropriate target, item, and remove directives. |
mkobj_X | Scripts called mkobj_X are used to process *.X files and *.sfx files for which mkobj_sfx has been mapped to mkobj_X (usually in the qsl_init file) using qsg keyword mapscript or by setting @QsgMap[script] in a qvrs file. |
Supporting QSG Library Scripts | |
![]() |
The following scripts are provided by the standard library for use by other scripts. |
mkobj | This script is used to output commands to construct objects. It outputs the qef directives to create a File's object file (e.g., File.o), its assembler file (e.g., File.s), its cpp output (e.g., File.o). |
generic |
This qsg script is used to output qef directives and recipes
to build and optionally install a file with a specified recipe.
This script is commonly used when the file's processing is non-standard.
finstall is invoked to install the file if the ![]() |
target |
target file description outputs the qef #target line:
#target file descriptionbut only if there has not been a previous output for the same target. |
item |
item file1 file2 ... outputs the qef #item line:
#item file1 file2 ...but only if there has not been a previous output for the arguments. #target and #item lines are output by qef when the ![]() |
rmfiles | This script outputs #rm{obj,inst,objpat,instpat} directives to remove the named or pattern matched files when one of the Remove* qef directives is specified. |
putdeps & strdep | These scripts are used to output dependencies. putdeps is for prerequisite files whereas strdep is for strings. A string dependency will be stored in the history file. If the string dependency's value is changed, the target will be deemed out-of-date. String dependencies are normally used to store values that are not part of the recipe but will be used by the recipe's processes (e.g., an environment variable). |
Further Examples and User Contributed Scripts | |
![]() |
The qsg libraries misc and dtree
are a rich source of example scripts for a variety of languages.
To get a list of the scripts for these libraries use:
% x-qsg -L \*dtree_qsl \*misc_qslTo retrieve the source for a specific script, use: % qsgdump -llib script |
![]() |
We should not leave this chapter without a brief discussion of
the use of qsg to produce and manage this guide.
qsg, despite being a fairly simple language, is exceedingly
useful and no example is probably better than the role that qsg
plays in producing a guide like this both in its web and printed forms.
This text is written in qsg using the html library, which will be replaceable by an XML library in the future. This permits the use of variables such as @QSG which has been set to "@<tool qsg>" and will be translated into: <a href="appendix-D.html#qsg"><i>qsg</i></a>that is: qsg. Chapter, section, and labels headings appear as: chapter -inum @(flags pn) Title ... @#The example commands such as: % qsg -c hanoi 3 # run 3 ring tower of hanoithat appear some 350 times in this guide are encoded as "@<cmd command # comment>". A ![]() << ... The text is just entered using the ... ><label Command In Middle of Output More text, some in @<b bold> ... ... >>So much for the source. The qeffile contains in part: gset PageMap @(call readlist @(findfile page.map)) if @(option PrintVersion) qsg2html @argv else qsg2html -d @{_DestDir_}/pages @argv fiThe page.map file contains the mapping of source file names (e.g., c080.qh) to section names (e.g., chapter-09.html). The qvrs option PrintVersion is used to suppress installation of the galley versions and suppress the links in the pages. The qsg2html script will generate mimk dependencies and recipes for each of the source files, such as: c080.html:P: _S_(c080.qh) _DestDir_/lib/qsg/guide.qsl \ <qtree>/lib/qsg/html.qsl qsg -lguide -o c080.html -c _S_(c080.qh) \ -p chapter-08.html -n chapter-10.html #rmobj c080.htmlThe web versions are produced and installed employing the same mechanism in a sibling directory using a spliced source path. Note that Appendices E through G are generated by x_db databases queries processed by qsg to produce HTML representations and the embedded links.
Yet another qsg script is used to invoke netscape Finally qsg scripts are used to create the installation packages and book production forms. Hence a single qef command will install the web pages, produce the book form, create the distribution package, and do the Chapter 10: file system integrity check via the simple application of a few qsg scripts. For your edification, the frequently referenced hanoi source is listed below for those who have not as yet installed the Q-Tree: % qsgdump -S hanoi summary [-] n [from to spare] run the towers of hanoi for N rings N number of rings to be moved from name of origin tower to name of target tower spare name of spare tower Well why not? If names of towers not provided, default names used. This script is provided for illustration and testing. endsummary proc hanoi [-] if @argv qsg is a remarkably useful little tool and it is fun to use. |
c080.qh - 9.5 - 04/01/20 |
![]() ![]() ![]() ![]() ![]() |