Trailing-Edge
-
PDP-10 Archives
-
DEC_CMS-20_V1.0_SRC
-
cms/sources/comand.bli
There are no other files named comand.bli in the archive.
module comand ( ! Command language processor for all commands
ident = '1',
%if
%bliss(bliss32)
%then
language(bliss32),
addressing_mode(external=long_relative,
nonexternal=long_relative)
%else
language(bliss36)
%fi
) =
begin
!
! COPYRIGHT (C) 1982 BY
! DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.
!
! THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED
! ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE AND WITH THE
! INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE OR ANY OTHER
! COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
! OTHER PERSON. NO TITLE TO AND OWNERSHIP OF THE SOFTWARE IS HEREBY
! TRANSFERRED.
!
! THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE
! AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT
! CORPORATION.
!
! DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ITS
! SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL.
!
!++
! Facility: CMS Library Processor
!
! Abstract:
!
! The purpose of this module is to hide the syntax of the
! commands from the routines that perform command actions.
!
!
! Environment: Transportable
!
! Author: Earl Van Horn Creation Date: April, 1979
!
!--
!
! Table of Contents:
!
forward routine
append_block : novalue, ! Append a block to a linked list.
comand, ! Gets a command and parses it.
curcom : novalue, ! Re-supplies parsing of current command.
find_com_gram, ! Finds a (sub-)command entry in the
! grammar table.
qualifiers, ! Recognizes one or more qualifiers.
scan_qual_codes : novalue, ! Find a series of qualifier codes in the
! grammar table.
user_remark ; ! Recognizes a user remark.
!
! Include Files:
!
%if %bliss(bliss32) %then
library 'sys$library:starlet';
%fi
%if %bliss(bliss36) %then
require 'jsys:';
%fi
library 'XPORT:' ;
require 'BLISSX:' ;
require 'COMUSR:' ; ! Declarations for the user of this module.
require 'LANGME:' ; ! Declarations of mechanisms internal to
! the language processor.
require 'ZONUSR:' ; ! Declarations for user of zones.
!
! Macros:
!
!
! Equated Symbols:
!
!
! Global and Own Storage:
!
global
! Zone for allocating command processor stuff.
comzon : new_zone ;
own ! Storage allowing CURCOM to return the parsing of the current command.
! The data structures pointed to are allocated in COMZON.
command_code, ! Integer code for the current command name.
a_first_command_qualifier, ! Address of first qualifier block in the list
! of command qualifiers. K_NULL means there
! are no command qualifiers.
a_first_parameter, ! Address of first parameter block in the list
! of command parameters. K_NULL means there
! are no parameters.
a_remark_descriptor, ! Address of remark descriptor. K_NULL means
! the command does not take a remark.
sub_command_code, ! Integer code for the sub-command. Zero means
! the command had none.
successful_parse : initial(false) ; ! True means successful parse ocurred.
!
! External References:
!
external literal
s_ambig,
s_extra,
s_invqual,
s_notoption,
s_quotenot;
external
gratab : gratab_vector, ! Grammar table.
usr_cmd : desc_block; !user command entered
external routine
abbrev, ! Find all matches for an abbreviation.
ask, ! Get a response from the user.
bldcom, !
bug, ! Report a bug.
codspl, ! Get spelling of a keyword.
enquot, ! Enclose in quotation marks.
ers, ! Report a user mistake.
fresad : novalue, ! Free a string allocated by ASK.
getcom, ! Obtain the user's command string.
nxtgra, ! Find the next entry in GRATAB.
nxtlex, ! Identify the next lexeme.
peekch, ! Test the next command character.
prevbl, ! Was previous char. a space or tab?
reclog, ! Recognize a /log or /nolog
recpar, ! Recognize a parameter.
rectst, ! Recvnize a special test qualifier.
recval, ! Recognize a qualifier value.
zalloc, ! Allocate storage.
zparam : novalue ; ! Set zone parameters
routine append_block(a_a_first_block, a_new_block) : novalue =
!++
! Functional Description:
!
! This routine appends a new block to the end of a linked chain of
! blocks. The link address is assumed to be the first item in each block.
! A link address of K_NULL ends the chain. If the chain is empty, the
! new block becomes the first block. The link address of the new
! block is not disturbed.
!
! Formal Parameters:
!
! a_a_first_block:The address of a fullword containing the address
! of the first block of the chain to be appended to.
! If the fullword is K_NULL, the new block is the first
! block of the chain, and the fullword is set to
! its address.
! a_new_block: The address of a block to be appended to the chain.
!
! Implicit Inputs:
!
! None
!
! Implicit Outputs:
!
! None
!
! Routine Value:
! Completion Codes:
!
! None
!
! Side Effects:
!
! None
!
!--
begin ! APPEND_BLOCK
$field
next = [$address] ; ! The address of the next block is
! always the first item in a block.
bind
a_first_block = .a_a_first_block,
new_block = .a_new_block: block field(next) ;
if .a_first_block eql k_null
then
a_first_block = new_block
else
begin ! Not the first.
local
r_this_block : ref block field(next) ;
r_this_block = .a_first_block ;
while .r_this_block[next] neq k_null do
r_this_block = .r_this_block[next] ;
r_this_block[next] = new_block ;
end ; ! Not the first.
end ; ! APPEND_BLOCK
global routine comand(a_com, a_sub,
a_a_first_qual, a_a_first_param, a_a_remark) =
!++
! Functional Description:
!
! COMAND obtains the user's command line and parses it, checking
! for syntax errors. If the user made no mistakes, the
! constituents of the command are passed back to the caller
! using the fullwords supplied as parameters, and TRUE is returned.
!
! The parameters and qualifiers of the command are represented by lists
! of data blocks allocated by COMAND and defined in COMUSR.REQ.
! The text of each parameter and the value, if any, of each qualifier,
! are character strings denoted by descriptors in the corresponding
! data blocks. In addition, certain parameters and qualifier values are
! described by parse trees using tree node blocks defined in COMUSR.REQ.
!
! Each parameter, qualifier value, and user remark has leading and
! trailing spaces and tabs removed before being passed back to the caller.
! In addition, the lexical rules of the command language are
! enforced, which means that most constructs also have no embedded spaces
! or tabs.
!
! The following constructs are converted to upper case
! before being passed back to the caller:
!
! generation-ref
! element-ref
! extended-file-name
! file-spec
!
! The following constucts are checked for correct form:
!
! generation-ref
! element-ref
! extended-file-name
!
! Note that file specifications are not checked for correct form.
!
! In Release Zero, the only construct for which a tree is provided
! is the generation reference. See COMUSR.REQ for information on
! the form of this tree.
!
! If the user made some mistakes, one or more messages describing them
! are written to the terminal error stream, and FALSE
! is returned. In this case, the fullwords supplied as parameters
! have undefined content.
!
! Formal Parameters:
!
! a_com : Address of a fullword in which the integer code
! for the command will be stored. These codes are
! defined in COMUSR.REQ.
! a_sub : Address of a fullword in which the integer code
! for the sub-command will be stored. These codes are
! defined in COMUSR.REQ. If the command has no
! sub-command, zero is stored.
! a_a_first_qual: Address of a fullword in which COMAND will store either
! the address of the first qualifier block for the
! command as a whole, or K_NULL if the command has no
! qualifiers. Qualifier blocks are defined in COMUSR.REQ.
! a_a_first_param:Address of a fullword in which COMAND will store either
! the address of the first parameter block for the
! command, or K_NULL if the command has no
! parameters. Parameter blocks are defined in COMUSR.REQ.
! a_a_remark: Address of a fullword in which COMAND will store either
! the address of a descriptor for the user's remark, or
! K_NULL if the command cannot have a user remark. Note
! that a missing remark in a command that can have one
! is reported as a remark of zero length.
!
! Implicit Inputs:
!
! The GRATAB and SPLTAB vectors, declared in module GRAMAR.
!
! Implicit Outputs:
!
! None
!
! Routine Value:
! Completion Codes:
!
! TRUE is returned if the user made no mistake, and otherwise FALSE.
!
! Side Effects:
!
! Many data structures are allocated in zone COMZON, using ZALLOC.
!
! Also, the values returned by a successful parse are stored in own
! variables declared in the head of this module. These values enable
! CURCOM to return the same values returned by COMAND.
!
!--
begin ! COMAND.
bind
com = .a_com,
sub = .a_sub,
r_first_qual = .a_a_first_qual : ref qualifier_block,
r_first_param = .a_a_first_param : ref parameter_block,
r_remark = .a_a_remark : ref desc_block ;
local
dummy, ! Receives a parameter qualifier list
! that must be empty.
first_com_qua_x, ! Index of first command qualifier
! item in GRATAB.
last_com_qua_x, ! Index of last command qualifier
! item in GRATAB.
optional, ! Means an optional parameter group
! is being processed.
option_present, ! Means the user has supplied something
! for an optional parameter group.
r_param : ref parameter_block, ! Address of current parameter block.
repeating, ! Means a repeatable parameter group
! is being processed.
repeat_x, ! Index of the start of the repeatable
! group in GRATAB.
this_x; ! Index of current item in GRATAB.
routine bug_in_table(a_trouble, a_rest) : novalue =
bug(cat(.a_trouble, ' before processing ', .a_rest)) ;
! A_REST is passed to avoid an up-level reference.
! Initialize each output parameter execpt COM.
sub = 0 ;
r_first_qual = k_null ;
r_first_param = k_null ;
r_remark = k_null ;
! Initialize the zone for command processor data.
%if not %bliss(bliss16)
%then zparam(comzon, 1000, 500, 0) ;
%fi ! Otherwise use the defaults.
! Find the GRATAB entry for this (sub-)command.
if not find_com_gram(usr_cmd, this_x)
then
return false ;
! Set the COM and SUB output parameters.
com = .gratab[.this_x] ;
this_x = .this_x + 1 ;
if .gratab[.this_x] geq k_sub_command_1
and .gratab[.this_x] leq k_sub_command_n
then
begin ! Sub-command.
sub = .gratab[.this_x] ;
this_x = .this_x + 1 ;
end ; ! Sub-command.
! See if the (sub-)command as a whole can have any qualifiers.
scan_qual_codes(this_x, first_com_qua_x, last_com_qua_x) ;
! Process all the qualifiers typed just after the (sub-)command.
if not qualifiers(usr_cmd, .first_com_qua_x, .last_com_qua_x, 0, -1,
r_first_qual, dummy)
then
return false ;
if .dummy neq k_null
then
bug(lit('Parameter qualifier list is not empty')) ;
! Interpret the grammar table for parameters and a user remark.
optional = false ;
option_present = false ;
repeating = false ;
while .gratab[.this_x] neq k_end_com_mark do
begin ! Interpret one item and advance to the next.
selectone .gratab[.this_x] of
set ! One item in grammar table.
[k_beg_opt_mark]:
begin ! Begin optional.
if .optional
then
bug_in_table(lit('Begin option mark'), usr_cmd) ;
optional = true ;
option_present = (.usr_cmd[desc_len] gtr 0
and not peekch(usr_cmd, lit('"'))) ;
end ; ! Begin optional
[k_end_opt_mark]:
begin ! End optional.
if not .optional
then
bug_in_table(lit('End option mark'), usr_cmd) ;
optional = false ;
option_present = false ;
end ; ! End optional.
[k_beg_rep_mark]:
begin ! Begin repeating.
if .repeating
then
bug_in_table(lit('Begin repeat mark'), usr_cmd) ;
repeating = true ;
repeat_x = .this_x ;
end ; ! Begin repeating.
[k_end_rep_mark]:
if not .repeating
then
bug_in_table(lit('End repeat mark'), usr_cmd) ;
! REPEATING is set to FALSE below.
[k_end_gram_mark]:
bug_in_table(lit('End of grammar'), usr_cmd) ;
[k_beg_com_mark]:
bug_in_table(lit('Command mark'), usr_cmd) ;
[k_remark_syn]:
begin ! Process remark.
if not user_remark(usr_cmd, r_remark)
then
return false ;
end ; ! Process remark.
[otherwise]:
begin ! Handle a parameter entry and its qualifier entries.
if (if not .optional then true else .option_present)
then
begin ! Process a parameter.
! Recognize and parse the parameter.
if not recpar(usr_cmd, .gratab[.this_x], r_param)
then
return false ;
! Process all qualifiers just after the parameter.
begin ! Receive qualifiers.
local
a_first_par_qua, ! Address of first qualifier
! block for this parameter.
first_par_qua_x, ! Index of first qualifier code
! in the GRATAB array, else 0.
last_par_qua_x ; ! Index of last qualifier code
! in the GRATAB array, else 0.
this_x = .this_x + 1 ;
scan_qual_codes(this_x, first_par_qua_x,
last_par_qua_x) ;
if not qualifiers(usr_cmd,
.first_com_qua_x, .last_com_qua_x,
.first_par_qua_x, .last_par_qua_x,
r_first_qual, a_first_par_qua)
then
return false
else
r_param[par_a_qual] = .a_first_par_qua ;
! PAR_A_QUAL may not be a
! fullword.
this_x = .this_x - 1 ; ! Increment to next GRATAB
! entry is always done below.
end ; ! Receive qualifiers.
! Add the parameter to the list.
append_block(r_first_param, .r_param) ;
end ; ! Process a parameter.
end ; ! Handle a parameter entry and its qualifier entries.
tes ; ! One item in grammar table.
! Advance to the next item in the grammar table.
if .gratab[.this_x] neq k_end_rep_mark
then
this_x = .this_x + 1
else
begin ! End of one repeat pass.
if .usr_cmd[desc_len] eql 0 or peekch(usr_cmd, lit('"'))
then
begin ! No more repititions.
this_x = .this_x + 1 ;
repeating = false ;
end ! No more repititions.
else
this_x = .repeat_x + 1 ; ! Go back for another pass.
end ; ! End of one repeat pass.
end ; ! Interpret one item and advance to the next.
! All input should have been processed.
if .usr_cmd[desc_len] gtr 0
then
begin ! Report superfluity.
ers(s_extra,cat(usr_cmd, (' is superfluous'))) ;
return false ;
end ; ! Report superfluity.
! Set the own variables for CURCOM.
command_code = .com ;
sub_command_code = .sub ;
a_first_command_qualifier = .r_first_qual ;
a_first_parameter = .r_first_param ;
a_remark_descriptor = .r_remark ;
successful_parse = true ;
true ! Successful parse.
end ; ! COMAND.
global routine curcom(a_com, a_sub,
a_a_first_qual, a_a_first_param, a_a_remark) : novalue =
!++
! Functional Description:
!
! This routine returns the same results as COMAND, provided COMAND
! successfully parsed the command and returned TRUE. Otherwise a
! bug is reported.
!
! Formal Parameters:
!
! See COMAND in this module.
!
! Implicit Inputs:
!
! Own variables in this module in which the results returned by
! COMAND are saved. Note that some of these variables are
! addresses of structures that COMAND allocates in COMZON, so
! COMZON must not have been freed before this routine is called.
!
! Implicit Outputs:
!
! None.
!
! Routine Value:
! Completion Codes:
!
! None
!
! Side Effects:
!
! None
!
!--
begin ! CURCOM
bind
com = .a_com,
sub = .a_sub,
r_first_qual = .a_a_first_qual : ref qualifier_block,
r_first_param = .a_a_first_param : ref parameter_block,
r_remark = .a_a_remark : ref desc_block ;
! Make sure this call is legal.
if not .successful_parse
then
bug(lit('Illegal call to CURCOM')) ;
! Copy the results to the caller's fullwords.
com = .command_code ;
sub = .sub_command_code ;
r_first_qual = .a_first_command_qualifier ;
r_first_param = .a_first_parameter ;
r_remark = .a_remark_descriptor ;
end ; ! CURCOM
routine find_com_gram(user_string, a_this_x) =
!++
! Functional Description:
!
! This routine obtains the command lexeme from the user string,
! and if the command has sub-commands, it obtains the sub-command
! lexeme. It finds the entry for the command, or for the command and its
! sub-command, in the GRATAB table, and delivers the index of this entry.
!
! If the user made any mistakes, he is told about them, and FALSE
! is returned.
!
! Formal Parameters:
!
! user_string: Address of descriptor of the user's command string.
! The descriptor is changed to identify the remainder
! of the command string, following the command and
! any sub-command.
! a_this_x: Address of a fullword in which the routine will store
! the index of the GRATAB entry for this (sub-)command.
! The index is that of the item containing the
! command code.
!
! Implicit Inputs:
!
! The GRATAB and SPLTAB vectors declared in module GRAMAR.
!
! Implicit Outputs:
!
! None
!
! Routine Value:
! Completion Codes:
!
! TRUE if the user made no mistake, otherwise FALSE.
!
! Side Effects:
!
! None
!
!--
begin ! FIND_COM_GRAM
map
user_string : ref desc_block;
bind
this_x = .a_this_x ;
local
all_matches : desc_block, ! All sub-commands that match what the
! user typed, separated by spaces.
found, ! Means a command has has been found
! that matches what the user typed.
i, ! Index of current GRATAB item.
lexeme : desc_block, ! Descriptor of command or
! sub-command lexeme.
r_com_spell : ref desc_block ; ! Address of descriptor of full command.
! Get the command lexeme.
if
not nxtlex(.user_string, k_normal_lex, k_null, lexeme)
then
bug(cat('NXTLEX returned to COMAND for ', .user_string)) ;
! Find the first grammar table entry for this command. The command is
! known to be correct and unambiguous because it has been checked by
! COMCOD, which is called when dispatching to the caller of COMAND.
this_x = 0 ; ! Start at the beginning of GRATAB.
found = false ;
while nxtgra(this_x) do
begin ! Examine one entry in the grammar table.
! Get the full spelling of the command.
r_com_spell = codspl(.gratab[.this_x]) ;
! See if the user's lexeme abbreviates this command.
if 0 eql ch$diff(.r_com_spell[desc_ptr],
ch$find_sub(len_comma_ptr(.r_com_spell), len_comma_ptr(lexeme)))
then
begin ! Found the command.
found = true ;
exitloop ;
end ; ! Found the command.
end ; ! Examine one entry in the grammar table.
if not .found
then
bug(cat('COMAND could not find ', lexeme)) ;
! .THIS_X now indicates the desired entry, or a candidate if the command
! has sub-commands.
if .gratab[.this_x + 1] geq k_sub_command_1 and
.gratab[.this_x + 1] leq k_sub_command_n
then
begin ! The command has sub-commands.
! Get the sub-command lexeme
! (see if we need to prompt)
if
.user_string[desc_len] eql 0
then
begin
local
sub_string : ref desc_block;
do
sub_string=ask(prompt_lit('Option'))
until
.sub_string[desc_len] neq 0;
!Add the string to the command line text
bldcom(.sub_string)
end;
if
not nxtlex(.user_string, k_normal_lex, lit('option'), lexeme)
then
return false ;
! Find out which sub-command(s) it matches.
i = .this_x ;
$str_desc_init(descriptor = all_matches, string = (0, k_null)) ;
do
begin ! Examine one sub-command entry in the grammar table.
! Make sure we are still looking at the same command.
if .gratab[.i] neq .gratab[.this_x]
then
exitloop ;
! See if the lexeme matches this sub-command.
if abbrev(lexeme, codspl(.gratab[.i + 1]), all_matches, comzon)
then
this_x = .i ; ! A new candidate.
end ! Examine one sub-command entry in the grammar table.
while nxtgra(i) ;
if .all_matches[desc_len] eql 0
then
begin ! No matching sub-command.
ers(s_notoption,cat(lexeme, ' is not an option of ',
.r_com_spell)) ;
return false ;
end ; ! No matching sub-command.
if not ch$fail(ch$find_ch(len_comma_ptr(all_matches), %c' '))
then
begin ! Ambiguous sub-command.
ers(s_ambig,cat(lexeme, ' could mean: ', all_matches));
return false ;
end ; ! Ambiguous sub-command.
! .THIS_X now designates the one matching sub-command entry in GRATAB.
end ; ! The command has sub-commands.
true
end ; ! FIND_COM_GRAM
routine qualifiers(a_user_string,
first_com_qua_x, last_com_qua_x,
first_par_qua_x, last_par_qua_x,
a_a_first_com_q, a_a_first_par_q) =
!++
! Functional Description:
!
! This routine recognizes the qualifiers and their values, if any, that
! occur next in the user's input string, and advances the string
! descriptor past the information recognized. Each qualifier
! is represented by a qualifier block, which is appended to
! one of two chains, depending on whether the qualifier applies
! to the command as a whole, or to the most recent parameter.
!
! The qualifiers allowed at this point in the input string are
! defined by two pairs of indexes in the GRATAB array. One pair
! defines the command qualifiers, and the other defines the
! parameter qualifiers.
!
! If a qualifier appears more than once in a command, the most recent
! occurrence is used. There is no significance to the order of
! qualifiers in their chains.
!
! Formal Parameters:
!
! a_user_string: Address of a descriptor for the string to be
! examined for leading qualifiers. This descriptor
! will be advanced by NXTLEX over the qualifiers
! processed.
! first_com_qua_x:Index of the first in a series of adjacent GRATAB
! entries that contain integer codes for the command
! qualifiers allowed at this point.
! last_com_qua_x: Index of the last entry in the above series. If the
! last index is less than the first index, no command
! qualifiers are allowed.
! first_par_qua_x:Index of the first in a series of adjacent GRATAB
! entries that contain integer codes for the parameter
! qualifiers allowed at this point.
! last_par_qua_x: Index of the last entry in the above series. If the
! last index is less than the first index, no parameter
! qualifiers are allowed.
! a_a_first_com_q:Address of a fullword containing the address of the
! first of a chain of qualifier blocks for the command
! qualifiers already recognized. The form of the
! qualifier blocks is declared in COMUSR.REQ. If
! additional command qualifers are found in the user
! string, their blocks will be appended to this
! chain. If the fullword contains K_NULL, no command
! qualifiers have been found yet. If the routine
! now finds some command qualifiers, the chain will
! be started, i.e., the contents of the fullword will
! be replaced by the address of the first of a chain
! of qualifier blocks.
! a_a_first_par_q:Address of a fullword in which this routine will
! store either K_NULL or the address of the first of a
! chain of qualifier blocks for the parameter qualifiers
! found in the user string.
!
! Implicit Inputs:
!
! GRATAB declared in module GRAMAR
!
! Implicit Outputs:
!
! None
!
! Routine Value:
! Completion Codes:
!
! FALSE if the user made a mistake, otherwise TRUE.
!
! Side Effects:
!
! Qualifier blocks are allocated in COMZON.
!
!--
begin ! QUALIFIERS
bind
user_string = .a_user_string : desc_block,
r_first_com_qua = .a_a_first_com_q : ref qualifier_block,
r_first_par_qua = .a_a_first_par_q : ref qualifier_block ;
local
all_matches : desc_block, ! The matching qualifiers, separated
! by spaces.
first_qua_x, ! Index of first GRATAB entry scanned.
found_special, ! RECTST found special test qualifier.
found_log, ! RECLOG found /log or /nolog
is_command_qual, ! Means qualifier is command qualifier.
last_qua_x, ! Index of last GRATAB entry scanned.
p_slash, ! Char. pointer to slash in user string.
qualifier_code, ! Integer code for a qualifier found.
r_qua : ref qualifier_block, ! Address of qualifier block for the
! qualifier currently being recognized.
user_spell : desc_block ; ! Descriptor of a slash followed by
! the user's spelling of the qualifier's
! name.
label
process_one_qualifier ;
! Initialize.
r_first_par_qua = k_null ;
! Process each leading qualifier in the user string.
while peekch(user_string, lit('/')) do
process_one_qualifier:
begin ! Process one qualifier.
! Recognize and process any special test qualifiers.
if not rectst(user_string, found_special)
then
return false ; ! User mistake.
if .found_special
then
leave process_one_qualifier ; ! Look for another slash.
! Recognize and process any log-related qualifiers
if not reclog(user_string, found_log,
.first_com_qua_x, .last_com_qua_x,
.first_par_qua_x, .last_par_qua_x )
then
return false; ! User mistake
if .found_log
then
leave process_one_qualifier ; ! Look for another slash
! Eat up the slash, but remember where it was.
if not nxtlex(user_string, k_normal_lex, k_null, user_spell)
then
bug(lit('NXTLEX returned to QUALIFIERS')) ;
p_slash = .user_spell[desc_ptr] ;
! Get the qualifier name.
if not nxtlex(user_string, k_normal_lex, lit('qualifier name'),
user_spell)
then
return false ;
! Let the descriptor denote the slash followed by the name.
user_spell[desc_ptr] = ch$plus(.user_spell[desc_ptr], -1) ;
user_spell[desc_len] = .user_spell[desc_len] + 1 ;
! Make sure the slash abuts the name.
if ch$diff(.user_spell[desc_ptr], .p_slash) gtr 0
then
begin ! Move the slash.
ch$wchar(%c' ', .p_slash) ;
ch$wchar(%c'/', .user_spell[desc_ptr]) ;
end ; ! Move the slash.
! Find an unambiguous match with a qualifier.
$str_desc_init(descriptor = all_matches, string = (0, k_null)) ;
incr n from 1 to 2 do
begin ! Examine either command or parameter qualifiers.
if .n eql 1
then
begin ! Focus on command qualifiers.
first_qua_x = .first_com_qua_x ;
last_qua_x = .last_com_qua_x ;
end ! Focus on command qualifiers.
else
begin ! Focus on parameter qualifiers.
first_qua_x = .first_par_qua_x ;
last_qua_x = .last_par_qua_x ;
end ; ! Focus on parameter qualifiers.
! Examine one kind of qualifier.
incr i from .first_qua_x to .last_qua_x do
begin ! Examine one qualifier.
! See if the user's qualifier matches this one.
if abbrev(user_spell, codspl(.gratab[.i]),
all_matches, comzon)
then
begin ! Matching qualifier.
qualifier_code = .gratab[.i] ;
is_command_qual = (.n eql 1) ;
end ; ! Matching qualifier.
end ; ! Examine one qualifier.
end ; ! Examine either command or parameter qualifiers.
! Report invalid qualifier.
if .all_matches[desc_len] eql 0
then
begin ! Can't find it.
ers(s_invqual,cat(user_spell, ' is incorrect, or ',
'perhaps misplaced'));
return false ;
end ; ! Can't find it.
! Report ambiguous qualifier abbreviation.
if not ch$fail(ch$find_ch(len_comma_ptr(all_matches), %c' '))
then
begin ! Ambiguous qualifier.
ers(s_ambig,cat(user_spell, ' could mean: ',all_matches)) ;
return false ;
end ; ! Ambiguous qualifier.
! See if this qualifier has already been given.
r_qua = (if .is_command_qual
then .r_first_com_qua
else .r_first_par_qua) ;
until
if .r_qua eql k_null
then true
else .r_qua[qua_code] eql .qualifier_code
do
r_qua = .r_qua[qua_a_next] ;
! Use a previous block for the same qualifier, thus overriding its
! value, if any. Otherwise allocate a new block.
if .r_qua eql k_null
then
begin ! Get and append a new qualifier block.
r_qua = zalloc(k_qua_units, comzon) ;
r_qua[qua_code] = .qualifier_code ;
r_qua[qua_a_next] = k_null ;
append_block(if .is_command_qual
then r_first_com_qua
else r_first_par_qua,
.r_qua) ;
end ; ! Get and append a new qualifier block.
r_qua[qua_a_tree] = k_null ; ! Abandon any previous tree.
! Recognize and process any value for this qualifier.
if not recval(user_string, .r_qua)
then
return false ;
end ; ! Process one qualifier.
true
end ; ! QUALIFIERS
routine scan_qual_codes(a_this_x, a_first_qual_x, a_last_qual_x): novalue =
!++
! Functional Description:
!
! This routine looks for a series of qualifier codes at a given position
! in the GRATAB array. If qualifier codes are present, the given
! position must contain K_BEG_QUA_MARK. The series concludes with
! K_END_QUA_MARK. The indexes of the first and last qualifer codes
! are returned.
!
! If the given position does not contain K_BEG_QUA_MARK, it is assumed
! that no qualifier codes are present, and 0 and -1 are returned
! for the first and last indexes, respectively.
!
!
! Formal Parameters:
!
! a_this_x: Address of the index in the GRATAB array at which to
! look for K_BEG_QUA_MARK. If that code is found, this
! index will be changed to that of the entry one beyond
! the corresponding K_END_QUA_MARK.
! a_first_qual_x: Address of a fullword where the index of the first
! qualifier will be returned. Zero is returned if
! there are no qualifiers at this point in GRATAB.
! a_last_qual_x: Address of a fullword where the index of the last
! qualifier will be returned. -1 is returned if
! there are no qualifiers at this point in GRATAB.
!
! Implicit Inputs:
!
! The GRATAB vector declared in module GRAMAR.
!
! Implicit Outputs:
!
! None
!
! Routine Value:
! Completion Codes:
!
! None
!
! Side Effects:
!
! None
!
!--
begin ! SCAN_QUAL_CODES
bind
this_x = .a_this_x,
first_qual_x = .a_first_qual_x,
last_qual_x = .a_last_qual_x ;
if .gratab[.this_x] eql k_beg_qua_mark
then
begin ! Some qualifiers.
this_x = .this_x + 1 ;
first_qual_x = .this_x ;
while .gratab[.this_x] neq k_end_qua_mark do
this_x = .this_x + 1 ;
last_qual_x = .this_x - 1 ;
this_x = .this_x + 1 ;
end ! Some qualifiers.
else
begin ! No qualifiers.
first_qual_x = 0 ;
last_qual_x = -1 ;
end ; ! No qualifiers.
end ; ! SCAN_QUAL_CODES
routine user_remark(a_user_string, a_a_remark) =
!++
! Functional Description:
!
! This routine obtains a remark from the user. If the remainder of
! the command string begins with a quotation mark, the remark is the
! next quoted string in the command. (If the command string and its
! descriptor were most recently processed by NXTLEX, the remainder
! never begins with a space or tab.) If the remainder is empty, the
! user is prompted for remark text, and the text is enclosed in
! quotation marks (with embedded quotes doubled).
!
! The text of a remark may be empty.
!
! If the user made a mistake, FALSE is returned.
!
! Formal Parameters:
!
! a_user_string: Address of a descriptor for the string to be
! examined for a remark.
! a_a_remark: Address of a fullword where the address of a
! descriptor for the remark will be stored.
!
! Implicit Inputs:
!
! None
!
! Implicit Outputs:
!
! None
!
! Routine Value:
! Completion Codes:
!
! TRUE if the user made no mistakes, otherwise FALSE.
!
! Side Effects:
!
! A descriptor or a SAD block is allocated in COMZON by ZALLOC.
! The user may be interrogated with ASK.
!
!--
begin ! USER_REMARK
bind
user_string = .a_user_string : desc_block,
r_remark = .a_a_remark : ref desc_block ;
local
char, ! Character being examined.
p_finish, ! Pointer to last character not space or tab.
p_start, ! Pointer to first character not space or tab.
r_remark_text ; ! Address of descriptor of text obtained by
! prompting.
! Get the raw remark.
if peekch(user_string, lit('"'))
then
begin ! Remark in command line.
! Make sure the remark is preceded by a space or tab.
if not prevbl(user_string, k_remark_syn)
then
return false ;
! Allocate a descriptor and make it denote the remark.
r_remark = zalloc(k_desc_units, comzon) ;
if not nxtlex(user_string, k_quotation_lex, codspl(k_remark_syn),
.r_remark)
then
return false ;
end ! Remark in command line.
else if .user_string[desc_len] eql 0
then
begin ! Prompted remark.
r_remark_text = ask(prompt_lit('Remark')) ;
r_remark = enquot(.r_remark_text) ;
fresad(.r_remark_text) ;
end ! Prompted remark.
else
begin ! Non-quotation is present.
ers(s_quotenot,cat(user_string,' must be a quoted string')) ;
return false ;
end ; ! Non-quotation is present.
true
end ; ! USER_REMARK
end ! Module COMAND
eludom