%TITLE 'PARMAC' !++ ! FACILITY: ! PARSER - CLI Interface ! ! ABSTRACT: ! This module defines the macros used to set up the appropriate data ! structures for PARSER. PARSER acts as an interface to the ! CLI$ routines. The kinds of data structures which need to be ! built are mainly blocks describing the parameters and tables ! which describe the qualifiers taken by the command or parameters. ! ! AUTHORS: ! Antonino N.J. Mione, Rogelio Guardia, James Cheng ! UNDER THE ( CLOSE ) SUPERVISION OF NICK BUSH AND ROBERT MCQUEEN ! ! CREATION DATE: T.B.S. ! ! MODIFIED BY: THIS SPACE RESERVED FOR FUTURE USE. !-- ! ! TABLE OF CONTENTS: ! ! ! INCLUDE FILES: ! ! ! MACROS: ! MACRO DSC$D_DESC_BASE = 0, 0, 0, 0 %, ! Marker for beginning of descriptor %NAME('__QUAL_FLAG_LIST') = TAKES_VALUE, TAKES_PREFIX_NO, CAN_BE_LIST, STORAGE_IS_PARAMETER, STORAGE_IS_DESCRIPTOR, HAS_RANGE, VALUE_IS_SIGNED %, ! Macro to generate field defs for qualifier blocks %NAME('__GEN_QUAL_FLAG_FIELDS')[A_FLAG_LIST] = %NAME('QUAL$V_',%STRING(A_FLAG_LIST)) = [ $BIT ] ! Generate a flag %, ! Macro to generate field defs for parameter blocks %NAME('__GEN_PARM_FLAG_FIELDS')[A_FLAG_LIST] = %NAME('PARM$V_',%STRING(A_FLAG_LIST)) = [ $BIT ] ! Generate a flag %, %NAME('__GEN_QUAL_FLAGS')(A_FLAG_LIST) ! List of flags for which to generate literals = MACRO %NAME('__DO_IT') [THE_FLAGS] = %NAME('QUAL$M_',%STRING(THE_FLAGS)) = 1 ^ X_CTR, %NAME('PARM$M_',%STRING(THE_FLAGS)) = 1 ^ X_CTR, %NAME('QUAL$K_',%STRING(THE_FLAGS)) = X_CTR, %NAME('PARM$K_',%STRING(THE_FLAGS)) = X_CTR %ASSIGN(X_CTR, X_CTR + 1) %QUOTE %; COMPILETIME X_CTR = 0; LITERAL %NAME('__DO_IT')(A_FLAG_LIST); ! Lay out the literals UNDECLARE %QUOTE %QUOTENAME('__DO_IT'), X_CTR; %; ! ! The following set of field definitions is for a qualifier or parameter block. Both ! have the same format. Items included are: ! KEY_WORD - Descriptor pointing at keyword string ! STORAGE - Address of argument(s) parsed ! MAX_LENGTH - Maximum length of one argument ! MAX_ARGCOUNT - Maximum number of arguments allowed ! KEYS - Pointer to keyword table (if qualifier takes a keyword value) ! ROUTINE_NAME - Address of routine to read qualifier value ! FLAGS - Bits describing charactaristics of the parameter or qualifier ! LOWEST_VALUE - Address of Lowest value an argument may take ! HIGHEST_VALUE - Address of Highest value an argument may take ! ! A parameter block is nearly identical in layout. There are two extra ! fields tacked onto the end. They are: ! ! VALUE_ARRAY - An address of an array of qualifier storage ! pointers. They point to values for the local ! qualifiers which were associated with the parameter. ! VALUE_CNT_ARRAY - Address of an array which has the same function ! as the value-cnt array for a qualifier table. ! $FIELD QUALIF_FIELDS = SET QUAL$G_QBLOCK_BASE = [ $SUB_BLOCK(0) ], ! Marker for beginning of a qualifier block QUAL$D_KEYWORD = [ $BYTES(DSC$K_D_BLN) ], QUAL$A_STORAGE = [ $ADDRESS ], QUAL$W_MAX_LENGTH = [ $SHORT_INTEGER ], QUAL$W_MAX_ARGCOUNT = [ $SHORT_INTEGER ], QUAL$A_ARGS = [ $ADDRESS ], QUAL$A_ROUTINE = [ $ADDRESS ], QUAL$L_FLAGS = [ $BITS(%BPVAL) ], $OVERLAY(QUAL$L_FLAGS) %NAME('__GEN_QUAL_FLAG_FIELDS')(%NAME('__QUAL_FLAG_LIST')), $CONTINUE QUAL$A_RANGE_LOW = [ $ADDRESS ], QUAL$A_RANGE_HIGH = [ $ADDRESS ] TES; LITERAL QUALIFIER_BLOCK_SIZE = $FIELD_SET_SIZE; $FIELD PARAM_FIELDS = SET PARM$G_PBLOCK_BASE = [ $SUB_BLOCK(0) ], ! Marker for beginning of a parameter block PARM$D_KEYWORD = [ $BYTES(DSC$K_D_BLN) ], PARM$A_STORAGE = [ $ADDRESS ], PARM$W_MAX_LENGTH = [ $SHORT_INTEGER ], PARM$W_MAX_ARGCOUNT = [ $SHORT_INTEGER ], PARM$A_ARGS = [ $ADDRESS ], PARM$A_ROUTINE = [ $ADDRESS ], PARM$L_FLAGS = [ $BITS(%BPVAL) ], $OVERLAY(PARM$L_FLAGS) %NAME('__GEN_PARM_FLAG_FIELDS')(%NAME('__QUAL_FLAG_LIST')), $CONTINUE PARM$A_RANGE_LOW = [ $ADDRESS ], PARM$A_RANGE_HIGH = [ $ADDRESS ], PARM$A_VALUE_ARRAY = [ $ADDRESS ], PARM$A_VALUE_CNT_ARRAY = [ $ADDRESS ] TES; LITERAL PARAMETER_BLOCK_SIZE = $FIELD_SET_SIZE; %NAME('__GEN_QUAL_FLAGS')(%QUOTE %NAME('__QUAL_FLAG_LIST')); MACRO $PAR_BUILD_QUAL_TABLE (GLS,TABLE_NAME,LIST) = MACRO %NAME('__MAYBE')(GLOB,LOCL) = %IF (GLS EQL 1) %THEN GLOB %ELSE LOCL %FI %QUOTE %, %NAME('__CRUNCH') [THE_FLAGS] ! For each flag = %IF %NULL(THE_FLAGS) ! If no flags... %THEN 0 ! Make sure they get something %ELSE %NAME('QUAL$M_',THE_FLAGS) ! Light a flag %FI %QUOTE %, %NAME('__ASCID') (SOME_STRING) ! Build descriptor for this string = ! wherever it is requested. DSC$K_CLASS_S^24 + ! Build word with class DSC$K_DTYPE_T^16 + ! type and %CHARCOUNT(SOME_STRING), ! length of string UPLIT(%ASCII %STRING(SOME_STRING)) ! Address of the string %QUOTE %; KEYWORDMACRO %NAME('__GEN_ITEM') (KEY_WORD, ! Text of keyword for this entry STORAGE = 0, ! Pointer to storage for values MAX_LENGTH = 0, ! Maximum length of one value MAX_COUNT = 0, ! Maximum count of values qualifier can take ROUTINE_ARGS = 0, ! Routine arguments to be passed to routine ! PAR$PARSE_xxx in PARSER ROUTINE_NAME, ! Name of routine to do argument processing FLAGS, ! List of flags describing characteristics ! of this qualifier ! The next two fields are needed only if the ! HAS_RANGE flag is specified LOWEST_VALUE, ! Lowest value which an arg can take HIGHEST_VALUE) ! Highest value an arg can take = %NAME('__ASCID')(%QUOTE KEY_WORD), ! Make descriptor for keyword string STORAGE, ! Point to storage for arguments MAX_COUNT^16 + MAX_LENGTH, ! Set up max length and count ROUTINE_ARGS, %IF %NULL(ROUTINE_NAME) %THEN 0, %ELSE %NAME(ROUTINE_NAME), %FI ! This is routine to do argument processing %IF %NULL(FLAGS) %THEN 0, %ELSE 0 OR %NAME('__CRUNCH')(,%REMOVE (FLAGS)), ! Put those flags in their place %FI %IF %NULL(LOWEST_VALUE) %THEN ! Check if null %IF ( MAX_LENGTH LEQ 4 ) AND ( MAX_LENGTH GTR 0 ) %THEN ! Check if not grater than 4 bytes %IF ( QUAL$M_VALUE_IS_SIGNED AND (%IF %NULL(FLAGS) %THEN 0 %ELSE 0 OR %NAME('__CRUNCH')(,%REMOVE (FLAGS)) %FI) ) NEQ 0 %THEN (1 ^ ( MAX_LENGTH * %BPUNIT - 1)), ! if signed, low = - ( 2 ** (max_length -1 ) - 1 ) %ELSE 0, %FI ! else, if unsigned low = 0 %ELSE 0, %FI ! else, if unsigned low = 0 %ELSE ! if not null, UPLIT(LOWEST_VALUE), %FI ! Put in pointer to low value %IF %NULL(HIGHEST_VALUE) %THEN ! Check if null %IF ( MAX_LENGTH LEQ 4 ) AND ! Check if not greater than 4 bytes ( MAX_LENGTH GTR 0 ) ! and not <= 0 bytes %THEN %IF ( QUAL$M_VALUE_IS_SIGNED AND (%IF %NULL(FLAGS) %THEN 0 %ELSE 0 OR %NAME('__CRUNCH')(,%REMOVE (FLAGS)) %FI) ) NEQ 0 %THEN (1 ^ ( MAX_LENGTH * %BPUNIT - 1) - 1) ! if signed, high = %ELSE (1 ^ ( MAX_LENGTH * %BPUNIT) -1) %FI %ELSE 0 %FI ! else, if unsigned low = 0 %ELSE UPLIT(HIGHEST_VALUE) %FI ! Put in pointer to high value %QUOTE %; ! ! This macro does the iteration for the keyword macro (__GEN_ITEM). ! MACRO %NAME('__GEN_ENTRY') [ARGUMENTS_TO_OTHER_LEVEL] = %NAME('__GEN_ITEM')(%REMOVE(ARGUMENTS_TO_OTHER_LEVEL)) %QUOTE %; %NAME('__MAYBE')(%QUOTE GLOBAL) BIND %NAME(TABLE_NAME,'_QUAL_TABLE') = UPLIT (%NAME('__GEN_ENTRY')(LIST)); UNDECLARE %QUOTENAME('__GEN_ITEM'), %QUOTENAME('__ASCID'), %QUOTENAME('__CRUNCH'); COMPILETIME X_CTR = 0; ! ! This macro generates successive Literal names for each of the ! qualifiers in the table. ! KEYWORDMACRO %NAME('__GEN_ITEM') (KEY_WORD, ! The keyword is all we need here, ignore rest STORAGE, MAX_LENGTH = 0, MAX_COUNT = 0, ROUTINE_ARGS = 0, ROUTINE_NAME, FLAGS, LOWEST_VALUE, HIGHEST_VALUE) = ! Use the keywords to generate indices into the ! qualifier blockvector and the value_cnt array. ! Indices are of the form: ! table_name $K_ qual_keyword _QUAL_INDEX ! ! Where 'table_name' is the name given to the qualifier table and ! 'qual_keyword' is the particular qualifier. %NAME(TABLE_NAME,'$K_',KEY_WORD,'_QUAL_INDEX') = %NUMBER(X_CTR) %ASSIGN(X_CTR, X_CTR + 1) %QUOTE %; %NAME('__MAYBE')(%QUOTE GLOBAL) LITERAL %NAME('QUAL$K_',TABLE_NAME,'_MIN') = %NUMBER (X_CTR), ! Define the minimum %NAME('__GEN_ENTRY')(LIST), ! Define table indices %NAME('QUAL$K_',TABLE_NAME,'_MAX') = %NUMBER (X_CTR); ! Define the minimum UNDECLARE %QUOTE %QUOTENAME('__GEN_ITEM'), ! Kill off the macros %QUOTENAME('__GEN_ENTRY'), ! ... X_CTR; ! And counter %NAME('__MAYBE')(%QUOTE GLOBAL,%QUOTE OWN) %NAME(TABLE_NAME,'_QUAL_VALUE_CNTS') : ! Set up table with one value count for each qualifier VECTOR [ %NAME('QUAL$K_',TABLE_NAME,'_MAX') ] ! Initialize all of them to -1 INITIAL (REP %NAME('QUAL$K_',TABLE_NAME,'_MAX') OF (-1)); MAP %NAME(TABLE_NAME,'_QUAL_TABLE') : REF BLOCKVECTOR[ %NAME('QUAL$K_',TABLE_NAME,'_MAX'), ! # of elems in blockvector QUALIFIER_BLOCK_SIZE ] ! Size of qualifier block FIELD(QUALIF_FIELDS); ! Field names for block UNDECLARE %QUOTE %QUOTENAME('__MAYBE'); ! KILL MAYBE MACRO %, ! END OF $PAR_BUILD_QUAL_TABLE MACRO %NAME('__KEY_FLAG_LIST') = TAKES_PREFIX_NO %, %NAME('__GEN_KEY_FLAG_FIELDS') [A_FLAG_LIST] ! A list of flags for which to generate field defs = %NAME('KEY$V_',A_FLAG_LIST) = [ $BIT ] ! Generate a flag %, %NAME('__GEN_KEY_FLAGS') [A_FLAG_LIST] ! List of flags for which to generate literals = COMPILETIME X_CTR = 0; MACRO %NAME('__DO_IT') [THE_FLAGS] = %NAME('KEY$M_',%STRING(THE_FLAGS)) = 1 ^ X_CTR %ASSIGN(X_CTR, X_CTR + 1) %QUOTE %; LITERAL %NAME('__DO_IT')(A_FLAG_LIST); ! Lay out the literals UNDECLARE %QUOTE %QUOTENAME('__DO_IT'), X_CTR; %; ! The following set of field definitions is for keyword table entries. ! Items included are: ! KEYWORD - Descriptor pointing at keyword string ! FLAGS - Bits describing charactaristics of the keyword ! VALUE - Address of keyword value ! $FIELD KEYWORD_FIELDS = SET KEY$D_KEYWORD = [ $BYTES(DSC$C_Z_BLN) ], KEY$L_FLAGS = [ $BITS(%BPVAL) ], $OVERLAY(KEY$L_FLAGS) %NAME('__GEN_KEY_FLAG_FIELDS')(%NAME('__KEY_FLAG_LIST')), $CONTINUE KEY$A_VALUE = [ $ADDRESS ] TES; LITERAL KEYWORD_BLOCK_SIZE = $FIELD_SET_SIZE; MACRO $PAR_BUILD_KEY_TABLE (GLS,TABLE_NAME, LIST) = MACRO %NAME('__MAYBE')(GLOB,LOCL) = %IF (GLS EQL 1) %THEN GLOB %ELSE LOCL %FI %QUOTE %, %NAME('__CRUNCH') [THE_FLAGS] ! For each flag = %IF %NULL(THE_FLAGS) ! If no flags... %THEN 0 ! Make sure they get something %ELSE %NAME('KEY$M_',THE_FLAGS) ! Light a flag %FI %QUOTE %, %NAME('__ASCID') (SOME_STRING) ! Build descriptor for this string = ! wherever it is requested. DSC$K_CLASS_S^24 + ! Build word with class DSC$K_DTYPE_T^16 + ! type and %CHARCOUNT(SOME_STRING), ! length of string UPLIT(%ASCII %STRING(SOME_STRING)) ! Address of the string %QUOTE %; KEYWORDMACRO %NAME('__GEN_ITEM') (KEY_WORD, ! Text of keyword FLAGS, ! List of flags associated with keyword VALUE = 0) ! Value to return on seeing keyword = %NAME('__ASCID') (%QUOTE KEY_WORD), ! Descriptor for keyword %IF %NULL(FLAGS) %THEN 0, %ELSE 0 OR %NAME('__CRUNCH')(,%REMOVE (FLAGS)), %FI VALUE ! Value to return %ASSIGN(X_CTR, X_CTR + 1) ! Number of entries in the keyword table %QUOTE %; ! ! This macro does the iteration for the keyword macro (__GEN_ITEM). ! MACRO %NAME('__GEN_ENTRY') [ARGUMENTS_TO_OTHER_LEVEL] = %NAME('__GEN_ITEM')(%REMOVE(ARGUMENTS_TO_OTHER_LEVEL)) %QUOTE %; COMPILETIME X_CTR = 0; %NAME('__MAYBE') (%QUOTE GLOBAL) BIND %NAME(%STRING(TABLE_NAME),'_KEY_TABLE') = UPLIT (%NAME('__GEN_ENTRY')(LIST)); %NAME('__MAYBE') (%QUOTE GLOBAL) LITERAL %NAME('KEY$K_',TABLE_NAME,'_MAX') = X_CTR; ! Define the max UNDECLARE %QUOTE %QUOTENAME('__GEN_ENTRY'), ! Kill off the macros %QUOTENAME('__GEN_ITEM'), %QUOTENAME('__ASCID'), %QUOTENAME('__CRUNCH'), %QUOTENAME('__MAYBE'), X_CTR; ! END OF $PAR_BUILD_KEY_TABLE MACRO %; MACRO $PAR_BUILD_PARM_BLOCK (GLS,BLOCK_NAME,LIST) = MACRO %NAME('__MAYBE')(GLOB,LOCL) = %IF (GLS EQL 1) %THEN GLOB %ELSE LOCL %FI %QUOTE %, %NAME('__CRUNCH') [THE_FLAGS] ! For each flag = %IF %NULL(THE_FLAGS) ! If no flags... %THEN 0 ! Make sure they get something %ELSE %NAME('PARM$M_',THE_FLAGS) ! Light a flag %FI %QUOTE %, %NAME('__ASCID') (SOME_STRING) ! Build descriptor for this string = ! wherever it is requested. DSC$K_CLASS_S^24 + ! Build word with class DSC$K_DTYPE_T^16 + ! type and %CHARCOUNT(SOME_STRING), ! length of string UPLIT(%ASCII %STRING(SOME_STRING)) ! Address of the string %QUOTE %; KEYWORDMACRO %NAME('__GEN_ITEM') (KEY_WORD, ! Text of keyword for this entry STORAGE = 0, ! Pointer to storage for values MAX_LENGTH = 0, ! Maximum length of one value MAX_COUNT = 0, ! Maximum count of values qualifier can take ROUTINE_ARGS = 0, ! Routine arguments to be passed to routine ! PAR$PARSE_xxx in PARSER ROUTINE_NAME, ! Name of routine to do argument processing FLAGS, ! List of flags describing characteristics ! of this qualifier ! The next two fields are needed only if the ! HAS_RANGE flag is specified LOWEST_VALUE, ! Lowest value which an arg can take HIGHEST_VALUE, ! Highest value an arg can take VALUE_ARRAY, ! Points to array of storage pointers for ! any local qualifiers attatched to the ! parameter. VALUE_CNT_ARRAY) ! Points to array of counts for number ! of argument values in each storage ! area of VALUE_ARRAY = %NAME('__ASCID') (%QUOTE KEY_WORD), ! Make decriptor for keyword string STORAGE, ! Point to storage for arguments MAX_COUNT^16 + MAX_LENGTH, ! Set up max length and count ROUTINE_ARGS, ! Point to keyword table if any %IF %NULL(ROUTINE_NAME) %THEN 0, %ELSE %NAME(ROUTINE_NAME), %FI ! This is routine to do argument processing %IF %NULL(FLAGS) %THEN 0, %ELSE 0 OR %NAME('__CRUNCH')(,%REMOVE (FLAGS)), %FI %IF %NULL(LOWEST_VALUE) %THEN ! Check if null %IF ( MAX_LENGTH LEQ 4 ) AND ! Check if not grater than 4 bytes ( MAX_LENGTH GTR 0 ) %THEN %IF ( QUAL$M_VALUE_IS_SIGNED AND (%IF %NULL(FLAGS) %THEN 0 %ELSE 0 OR %NAME('__CRUNCH')(,%REMOVE (FLAGS)) %FI) ) NEQ 0 %THEN (1 ^ ( MAX_LENGTH * %BPUNIT - 1)), ! if signed, low = - ( 2 ** (max_length -1 ) - 1 ) %ELSE 0, %FI ! else, if unsigned low = 0 %ELSE 0, %FI ! else, if unsigned low = 0 %ELSE ! if not null, UPLIT(LOWEST_VALUE), %FI ! Put in pointer to low value %IF %NULL(HIGHEST_VALUE) %THEN ! Check if null %IF ( MAX_LENGTH LEQ 4 ) AND ! Check if not grater than 4 bytes ( MAX_LENGTH GTR 0 ) %THEN %IF ( QUAL$M_VALUE_IS_SIGNED AND (%IF %NULL(FLAGS) %THEN 0 %ELSE 0 OR %NAME('__CRUNCH')(,%REMOVE (FLAGS)) %FI) ) NEQ 0 %THEN (1 ^ ( MAX_LENGTH * %BPUNIT - 1) - 1), ! if signed, high = %ELSE (1 ^ ( MAX_LENGTH * %BPUNIT) -1), %FI %ELSE 0, %FI ! else, if unsigned low = 0 %ELSE UPLIT(HIGHEST_VALUE), %FI ! Put in pointer to high value %IF %NULL(VALUE_ARRAY) %THEN 0, %ELSE VALUE_ARRAY, %FI ! Pointer to array of storage pointers %IF %NULL(VALUE_CNT_ARRAY) %THEN 0 %ELSE VALUE_CNT_ARRAY %FI ! Pointer to array of counts %QUOTE %; %NAME('__MAYBE') (%QUOTE GLOBAL) BIND %NAME(BLOCK_NAME,'_PARM_BLOCK') = UPLIT (%NAME('__GEN_ITEM')(%REMOVE (LIST))); MAP %NAME(BLOCK_NAME,'_PARM_BLOCK') : REF BLOCK[ PARAMETER_BLOCK_SIZE ] FIELD(PARAM_FIELDS); %NAME('__MAYBE') (%QUOTE GLOBAL, %QUOTE OWN) %NAME(BLOCK_NAME,'_PARM_VALUE_CNT') : INITIAL(-1); UNDECLARE %QUOTENAME('__GEN_ITEM'), %QUOTENAME('__ASCID'), %QUOTENAME('__MAYBE'), %QUOTENAME('__CRUNCH'); ! END OF $PAR_BUILD_PARM_BLOCK MACRO %; ! ! EQUATED SYMBOLS: ! ![~literal_declaration~] ![~bind_declaration~] ! ! OWN STORAGE: ! ![~own_declaration~] ![~global_declaration~] ! ! EXTERNAL REFERENCES: ! EXTERNAL ROUTINE PAR$INIT_QUALIFIER_TABLE, PAR$INIT_PARAMETER_BLOCK, PAR$PARSE_QUALIFIERS, PAR$PARSE_PARAMETER, PAR$PARSE_AN_ELEMENT, PAR$PARSE_FILE, PAR$PARSE_KEYWORD, PAR$PARSE_INTEGER, PAR$PARSE_STRING;