! EVE$PARSER.TPU 31-DEC-1992 11:55 Page 1 module eve$parser ident "V03-009" ! ! COPYRIGHT © 1986,1992 BY ! DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASSACHUSETTS ! ALL RIGHTS RESERVED ! ! 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: ! DECTPU - Text Processing Utility ! EVE - Extensible Versatile Editor ! ! ABSTRACT: ! This is the parser for the EVE command interface. ! ! ENVIRONMENT: ! OpenVMS VAX, OpenVMS AXP, RISC/ULTRIX ! ! CREATION DATE: 10-Sep-1988 !-- ! EVE$PARSER.TPU Page 2 !++ ! Table of Contents ! ! EVE$PARSER.TPU ! 31-DEC-1992 11:55 ! ! Procedure name Page Description ! -------------- ---- ------------ ! ! eve$$command_pre_filter 3 Key trap in Command Window ! eve$$command_post_filter 3 Key trap in Command Window ! eve$$enter_command_window 4 Enter the command window ! eve$$exit_command_window 5 Start processing the command ! eve$$set_command_line 6 Remember current command line ! eve$$repair_command_line 7 Repair current command line ! eve$process_command 8 Process a command ! eve_recall 9 Recall previous commands ! eve_do 10 The DO key procedure ! eve$$get_token 11 Get next token in the command line ! eve$$double_quotes 12 Handle quotes in commands ! eve$$add_final_string 13 Handle last command argument ! eve$$parse 14 The EVE parser ! eve$$enough_tokens 19 Give parser assistance ! eve$$parse_synonym 20 Test for cmd choice = a synonym root ! eve$parser_dispatch 21 Dispatcher for facility parsers !-- ! EVE$PARSER.TPU Page 3 procedure eve$$command_pre_filter ! Key trap in Command Window if current_window = eve$command_window then eve$$x_original_position := mark (FREE_CURSOR); endif; endprocedure; ! eve$$command_pre_filter procedure eve$$command_post_filter ! Key trap in Command Window local moved_position, ! Cursor position after executing the key stay_here, here; on_error [OTHERWISE]: endon_error; if get_info (eve$$x_prompt_range, "type") = RANGE then if (current_window = eve$command_window) and (get_info (current_window, "buffer") = get_info (eve$$x_prompt_range, "buffer")) then if not (get_info (current_buffer, "bound")) then position (TEXT); ! snap cursor to text if mark (NONE) <> end_of (current_buffer) then ! move over TAB chars if current_character = ascii (9) then if eve$test_synonym ("move_right", eve$$lookup_comment (last_key, eve$x_key_map_list )) then move_horizontal (1); endif; endif; endif; endif; if str (eve$$x_prompt_range) <> eve$x_command_prompt then here := mark (FREE_CURSOR); if get_info (here, "record_number") = get_info (beginning_of (eve$$x_prompt_range), "record_number") then stay_here := TRUE; ! stay on this line after correction endif; position (beginning_of (eve$$x_prompt_range)); erase (eve$$x_prompt_range); if get_info (mark (NONE), "unmodifiable_records") then ! just erased the entire line position (LINE_BEGIN); ! insure at bol split_line; ! makes modifiable line move_vertical (-1); endif; eve$$x_prompt_range := copy_text (eve$x_command_prompt); if not stay_here then position (here); endif; endif; if mark (NONE) = end_of (current_buffer) then move_horizontal (-1); endif; loop ! clean up bogus lines from bottom to top exitif index (current_line, eve$x_command_prompt) = 1; if get_info (eve$$x_original_position, "record_number") <> get_info (mark (FREE_CURSOR), "record_number") then set (RECORD_ATTRIBUTE, mark (NONE), MODIFIABLE, ON); erase_line; endif; exitif mark (NONE) = beginning_of (current_buffer); move_horizontal (-1); endloop; moved_position := mark (NONE); position (LINE_BEGIN); if mark (NONE) <> beginning_of (eve$$x_prompt_range) then position (eve$$x_original_position); eve$$repair_command_line; position (moved_position); eve$$set_command_line; ! calls eve$trim_line (moves to eol) if get_info (eve$x_found_range, "type") = RANGE then if get_info (eve$x_found_range, "buffer") = current_buffer then position (moved_position); endif; endif; else position (moved_position); endif; if current_offset < eve$x_command_prompt_length then move_horizontal (eve$x_command_prompt_length - current_offset); endif; endif; endif; endprocedure; ! eve$$command_post_filter ! EVE$PARSER.TPU Page 4 procedure eve$$enter_command_window ! Enter the command window ! Set up command line editor local saved_window, saved_mark; on_error [OTHERWISE]: eve$$restore_position (saved_window, saved_mark); endon_error; saved_window := current_window; saved_mark := mark (FREE_CURSOR); eve$$x_start_do_key := eve$$lookup_comment (last_key, ""); eve$check_bad_window; eve$$x_pre_command_window := current_window; eve$goto_command_window; position (end_of (eve$command_buffer)); if get_info (eve$command_buffer, "record_count") = 0 then ! make entire buffer unmodifiable except the current line copy_text (eve$x_command_prompt); set (RECORD_ATTRIBUTE, create_range (beginning_of (eve$command_buffer), end_of (eve$command_buffer), NONE), MODIFIABLE, OFF); set (RECORD_ATTRIBUTE, mark (NONE), MODIFIABLE, ON); else split_line; ! makes modifiable line move_vertical (-1); copy_text (eve$x_command_prompt); if get_info (eve$command_buffer, "record_count") <= 3 then ! insure initial "get file & @init_file" are made unmodifiable set (RECORD_ATTRIBUTE, create_range (beginning_of (eve$command_buffer), end_of (eve$command_buffer), NONE), MODIFIABLE, OFF); set (RECORD_ATTRIBUTE, mark (NONE), MODIFIABLE, ON); ! makes new line modifiable endif; endif; eve$$x_choice_range := 0; eve$$x_state_array {eve$$k_prompt_flag} := 0; ! set when cmd prompts for arg set (SHIFT_KEY, get_info (eve$x_key_map_list, "shift_key"), eve$x_command_key_map_list); eve$$set_command_line; endprocedure; ! eve$$enter_command_window ! EVE$PARSER.TPU Page 5 procedure eve$$exit_command_window ! Start processing the command ! Leave command line editor (unless parser finds an ambiguity, in which case, ! the choices are displayed in the choice window). local saved_window, ! For ^C cleanup if command was executed saved_mark, ! Maintain editing position in command buffer did_repair, ! Boolean set if called eve$$repair_command did_command, ! Boolean set if cmd was executed changed_window, ! Boolean set if on_error should change windows start_mark, ! Start of EVE$$X_CHOICE_RANGE end_mark, ! End of EVE$$X_CHOICE_RANGE current_command_line; ! String containing current command buffer line on_error [TPU$_CONTROLC]: if changed_window ! eve$check_bad_window moved from cmd_w then eve$$restore_position (eve$command_window, saved_mark); else if did_repair then ! save the current cmd in eve$$x_saved_command_line ! in case the user modified a previous command eve$$set_command_line; else if did_command ! command was executed, insure command window then ! is cleared saved_window := current_window; saved_mark := mark (FREE_CURSOR); position (end_of (eve$command_buffer)); update (eve$command_window); position (saved_window); position (saved_mark); endif; endif; endif; eve$learn_abort; abort; [OTHERWISE]: if changed_window ! eve$check_bad_window moved from cmd_window then eve$$restore_position (eve$command_window, saved_mark); else if did_repair then ! save the current cmd in eve$$x_saved_command_line ! in case the user modified a previous command eve$$set_command_line; else if did_command ! command was executed, insure command window then ! is cleared saved_mark := mark (FREE_CURSOR); position (end_of (eve$command_buffer)); update (eve$command_window); position (saved_mark); endif; endif; endif; endon_error; if current_window <> eve$command_window then eve$message (EVE$_NOTINCMD); else saved_mark := mark (NONE); ! padding is ok here changed_window := TRUE; if eve$check_bad_window ! position out of command window then if get_info (eve$$x_pre_command_window, "type") <> WINDOW then eve$$x_pre_command_window := current_window; endif; endif; position (eve$command_window); changed_window := FALSE; position (saved_mark); ! restore command buf editing position eve$$x_stop_do_key := eve$$lookup_comment (last_key, ""); current_command_line := current_line;! save the cmd & restore modified line eve$$repair_command_line; ! (may move saved_mark to next bol) did_repair := TRUE; position (end_of (eve$command_buffer)); move_vertical (-1); set (RECORD_ATTRIBUTE, mark (NONE), MODIFIABLE, ON); erase_line; split_line; ! makes modifiable line move_vertical (-1); copy_text (current_command_line); if substr (current_command_line, 1, eve$x_command_prompt_length) = eve$x_command_prompt then current_command_line := substr (current_command_line, eve$x_command_prompt_length + 1, length (current_command_line)); endif; end_mark := mark (NONE); move_horizontal (-length (current_command_line)); start_mark := mark (NONE); position (end_mark); eve$$x_choice_range := create_range (start_mark, end_mark, NONE); set (RECORD_ATTRIBUTE, mark (NONE), MODIFIABLE, OFF); eve$unmap_if_mapped (eve$choice_window); update (eve$$x_pre_command_window); eve$clear_message; eve$$x_prompt_range := 0; ! disable eve$$command_post_filter eve$$x_state_array {eve$$k_command_line_flag} := TRUE; position (eve$$x_pre_command_window); did_repair := FALSE; did_command := TRUE; ! ^C will now leave cursor in pre_command_window or the one the cmd moves to eve$parser_dispatch (current_command_line); ! may display choices + move to did_command := FALSE; ! window <> pre_command_window eve$$x_state_array {eve$$k_command_line_flag} := FALSE; endif; endprocedure; ! eve$$exit_command_window ! EVE$PARSER.TPU Page 6 procedure eve$$set_command_line ! Remember current command line ! Creates the prompt range, and store the current command line ! into a global variable. Makes the current command line modifiable. local bol_position; ! beginning of current line on_error [OTHERWISE]: endon_error; if current_window = eve$command_window then if mark (NONE) = end_of (current_buffer) then move_vertical (-1); endif; position (LINE_BEGIN); bol_position := mark (NONE); move_horizontal (eve$x_command_prompt_length - 1); eve$$x_prompt_range := create_range (bol_position, mark (NONE), eve$x_prompt_highlighting); set (RECORD_ATTRIBUTE, mark (NONE), MODIFIABLE, ON); eve$trim_line; ! goes to end of line eve$$x_saved_command_line := current_line; if eve$$x_saved_command_line = eve$x_command_prompt then eve$$x_saved_command_line := ""; endif; endif; endprocedure; ! eve$$set_command_line ! EVE$PARSER.TPU Page 7 procedure eve$$repair_command_line ! Repair current command line ! If the current command line is already modified, then ! restore the saved command line on_error [OTHERWISE]: endon_error; if current_window = eve$command_window then if (eve$$x_saved_command_line <> "") and (current_line <> eve$$x_saved_command_line) then erase_line; ! ^C messes up command buffer after here split_line; move_vertical (-1); copy_text (eve$$x_saved_command_line); eve$trim_line; endif; set (RECORD_ATTRIBUTE, mark (NONE), MODIFIABLE, OFF); endif; endprocedure; ! eve$$repair_command_line ! EVE$PARSER.TPU Page 8 procedure eve$process_command ! Process a command (new_do_line) ! String containing Eve command - input ! Process command selected in command line editor ! (called by eve$parser_dispatch that's called by eve$$exit_command_window) local valid_command, ! Clean parse or DO/DO saved_count, ! Repeat count we started with the_program, ! Compiled program to execute do_ix, ix, saved_window, saved_mark; on_error [TPU$_CONTROLC]: eve$$restore_position (saved_window); update (saved_window); eve$learn_abort; abort; [OTHERWISE]: eve$$restore_position (saved_window); update (saved_window); endon_error; saved_window := current_window; saved_mark := mark (FREE_CURSOR); if new_do_line <> "" then eve$x_do_line := new_do_line; eve$x_parsed_do_line := eve$$parse (eve$x_do_line); if eve$x_parsed_do_line = "" then ! message sent during parse error eve$x_do_line := ""; else valid_command := TRUE; endif; else eve$$x_state_array {eve$$k_ambiguous_parse} := FALSE; ! need this since eve$$parse is not called here if eve$test_synonym ("do", eve$$x_start_do_key) and eve$test_synonym ("do", eve$$x_stop_do_key) then if eve$x_do_line = "" then eve$message (EVE$_NOPREVCMD); else eve$message (EVE$_CMDAGAIN, 0, eve$x_do_line); valid_command := TRUE; endif; else eve$message (EVE$_NOEVECMD); ! If user gave ambiguous input file spec[s], but erased the command ! after seeing the choices, prevent applying command line qualifiers ! to any buffer created with a subsequent GET FILE. if eve$$x_ambiguous_input_file <> 0 then eve$message (EVE$_DISABLEQUALIFS); eve$$x_ambiguous_input_file := 0; endif; endif; endif; if not eve$$x_state_array {eve$$k_ambiguous_parse} then eve$goto_command_window; position (end_of (eve$command_buffer)); if new_do_line = "" then if mark (NONE) <> beginning_of (eve$command_buffer) then move_vertical (-1); set (RECORD_ATTRIBUTE, mark (NONE), MODIFIABLE, ON); erase_line; endif; endif; update (eve$command_window); position (saved_window); position (saved_mark); if valid_command then ! now execute the program the_program := compile (eve$$kt_return + eve$x_parsed_do_line); ! Loop if repeating a DO key; otherwise, execute once. eve$x_repeat_do ! indexes into eve$x_repeat_count that contains the repeat counts. ! Correct use of eve$x_repeat_count and eve$x_repeat_do arrays requires ! NOT keeping indexes in global variables, but getting last index into ! local variable. do_ix := get_info (eve$x_repeat_do, "last"); if do_ix = tpu$k_unspecified then ! Not repeating a DO key ! Not repeating a DO key execute (the_program); ! May set eve$$x_state_array saved_window := current_window; saved_mark := mark (FREE_CURSOR); else ix := eve$x_repeat_do {do_ix}; if eve$x_repeat_types {ix} <> DO then eve$message (EVE$_EVEINTERROR); eve$learn_abort; return (FALSE); endif; saved_count := eve$x_repeat_count {ix}; ! Use local copy of index (on stack) so we use correct count ! (REPEAT cmd will consume this count and set it to 1 so we stop) loop exitif eve$x_repeat_count {ix} = 0; if execute (the_program) = 0 ! May set eve$$x_state_array { then ! "ambiguous_parse"} eve$message (EVE$_REPEATSTOP); if eve$x_repeat_count = 0 then ! In case error did not call eve$learn_abort, and TPU ! zeroed our special_error_symbol variable, init ! the repeat variables. eve$init_repeat; return (FALSE); endif; if eve$x_repeat_count {ix} = tpu$k_unspecified then ! We are unwinding after an error, just return return (FALSE); endif; exitif; endif; ! remember where the command left us in case ^C saved_window := current_window; saved_mark := mark (FREE_CURSOR); ! Just in case the program did not return 0 if eve$x_repeat_count = 0 then ! Error did not call eve$learn_abort, and TPU ! zeroed our special_error_symbol variable, init ! the repeat variables. eve$init_repeat; return (FALSE); endif; if eve$x_repeat_count {ix} = tpu$k_unspecified then ! We are unwinding after an error, just return return (FALSE); endif; eve$x_repeat_count {ix} := eve$x_repeat_count {ix} - 1; endloop; eve$x_repeat_count {ix} := tpu$k_unspecified; eve$x_repeat_types {ix} := 0; eve$x_repeat_do {do_ix} := tpu$k_unspecified; endif; endif; endif; if eve$$x_state_array {eve$$k_ambiguous_parse} ! Can't combine with above then if eve$x_executing_file then ! dump any ambiguous /initialization or @file commands eve$$x_state_array {eve$$k_ambiguous_parse} := FALSE; position (end_of (eve$command_buffer)); if mark (NONE) <> beginning_of (eve$command_buffer) then move_vertical (-1); ! erase the ambiguous command erase_line; endif; position (saved_mark); return (FALSE); ! parser already output ambiguous message endif; if not get_info (COMMAND_LINE, "display") ! windows only when /display then ! User error, ambiguous command in /NODISPLAY mode...exit EVE. exit; ! get out now endif; eve$map_choices; eve$goto_command_window; position (end_of (eve$command_buffer)); move_horizontal (-1); eve$$set_command_line; endif; if eve$x_do_line = "" then return (FALSE); else return (TRUE); endif; endprocedure; ! eve$process_command ! EVE$PARSER.TPU Page 9 procedure eve_recall ! Recall previous commands ! VMS V4-style recall command local recall_line; ! String containing command line to be recalled on_error [TPU$_BEGOFBUF]: eve$$set_command_line; ! sets top line modifiable again eve$message (EVE$_NOMORE); position (LINE_END); eve$learn_abort; return (FALSE); [OTHERWISE]: endon_error; if not eve$declare_intention (eve$k_action_commands) then return (FALSE); endif; if current_window <> eve$command_window then eve$$enter_command_window; endif; ! make current line unmodifiable set (RECORD_ATTRIBUTE, mark (NONE), MODIFIABLE, OFF); move_horizontal (- (current_offset + 1)); eve$$set_command_line; ! sets line modifiable return (TRUE); endprocedure; ! eve_recall ! EVE$PARSER.TPU Page 10 procedure eve_do ! The DO key procedure (do_parameter) ! String containing Eve command - input ! Command line interpreter local do_line; ! Local copy of do_parameter on_error [OTHERWISE]: endon_error; if not eve$declare_intention (eve$k_action_commands) then return (FALSE); endif; do_line := do_parameter; if (length (do_line) > 0) then eve$parser_dispatch (do_line); else if current_window = eve$command_window then eve$$exit_command_window; else if current_window <> eve$prompt_window ! reject if prompting then if current_window = eve$choice_window then eve$$select_choice; position (eve$command_window); eve$$exit_command_window; else eve$$enter_command_window; endif; endif; endif; endif; return (TRUE); endprocedure; ! eve_do ! EVE$PARSER.TPU Page 11 procedure eve$$get_token ! Get next token in the command line ! Description ! EVE$$GET_TOKEN returns the next token in the command line or ! a null string if no more tokens. Normally leaves the cursor on ! the whitespace after a token; exceptions are: ! o will leave it on the "=" in DEFINE=, or DEFINE KEY= ! o will leave it on the character after the "@" in "@file_name" ! ! Tokens include symbols, quoted strings, and punctuation, and strings ! that are "none of the above." A quoted string at the end of a line ! does not have to have a final close quote. ! ! Special cases the "=" in the DEFINE KEY command. ! Special cases the "@" in the @ (ATFILE) command. User may enter the ! command "@file_name" which invoked EVE__AT_FILE(file_name) ! ! Implicit Inputs ! eve$$x_command_line Command entered ! eve$$x_command_index Index into eve$$x_command_line while parsing ! eve$$x_command_length Length of eve$$x_command_line ! ! Implicit Outputs ! eve$$x_state_array {eve$$k_is_symbol} Token only alphanumeric $ _ ! eve$$x_state_array {eve$$k_is_number} Token only numeric ! eve$$x_state_array {eve$$k_is_quoted_string} Token is a quoted string ! ! Return Value ! the token local original_index, ! Original index into command line quote_char, ! Quote character being used for quoted string c, ! Current character in command line closed_quote, ! True if quote_char ends quoted string saw_equals_sign; ! True if equal sign already encountered on_error [OTHERWISE]: endon_error; ! ! Default the state array variables ! eve$$x_state_array {eve$$k_is_number} := FALSE; eve$$x_state_array {eve$$k_is_symbol} := FALSE; eve$$x_state_array {eve$$k_is_quoted_string} := FALSE; ! ! Move eve$$x_command_index over whitespace. Stay put if not on whitespace ! when starting. If we reach the end of the command line, then return as ! having not found a token. ! loop if eve$$x_command_index > eve$$x_command_length then return ""; endif; c := substr (eve$$x_command_line, eve$$x_command_index, 1); exitif index (eve$$x_token_separators, c) = 0; eve$$x_command_index := eve$$x_command_index + 1; endloop; ! ! Save this non-whitespace index ! original_index := eve$$x_command_index; ! ! Handle special characters when obtaining the first token for a command. ! Being on the first token for a command is determined by the variable ! eve$$x_uppercase_token (which is the concatenation of all previous tokens ! for this command) being empty. ! if (eve$$x_uppercase_token = "") then ! ! If the character is an '_', then return that character as the token ! without bumping the index past it. This prevents the "_" in _AT_FILE ! from being used as a command. ! if (c = "_") then return "_"; endif; ! ! If the character is an '@', then return the token _AT_FILE and advance ! the index over the character. ! if (c = "@") then eve$$x_command_index := eve$$x_command_index + 1; eve$$x_state_array {eve$$k_is_symbol} := TRUE; return "_AT_FILE"; endif; endif; ! ! If the character is an '=', then set a flag that will tell us that we've ! already seen an equal sign. Otherwise, set the flag to false. ! saw_equals_sign := (c = '='); ! ! Process symbols. If the current character is a symbol character (defined in ! EVE$CORE to be letters, number, dollar sign and underscore), then process ! this token up to the next non-symbol character. ! ! The exception to this is when obtaining a key specifier on a DEFINE_KEY or ! an UNDEFINE_KEY command in which case we either use everything up to the next ! token separator or we terminate the string if we had not already seen the ! equals sign. ! ! The string "XXX=foo" will return the token XXX. The string "=foo" will return ! the token "=foo". ! if (index (eve$x_symbol_characters, c) > 0) or saw_equals_sign then eve$$x_state_array {eve$$k_is_number} := TRUE; eve$$x_state_array {eve$$k_is_symbol} := TRUE; loop ! ! If we are currently working on a number, then see if it's still true ! if eve$$x_state_array {eve$$k_is_number} then eve$$x_state_array {eve$$k_is_number} := (index (eve$x_digit_characters, c) <> 0); endif; ! ! If we are currently working on a symbol, then see if it is still a ! symbol. Question: This seems to contradict the definition of ! is_symbol at the top of this routine since the symbol characters ! include $, _, and numbers. ! if eve$$x_state_array {eve$$k_is_symbol} then eve$$x_state_array {eve$$k_is_symbol} := (index (eve$x_symbol_characters, c) <> 0); endif; ! ! Bump the character in the command to the next character. Exit if we ! run off the end of the command line. ! eve$$x_command_index := eve$$x_command_index + 1; exitif eve$$x_command_index > eve$$x_command_length; c := substr (eve$$x_command_line, eve$$x_command_index, 1); ! ! Exit if this character is a token separator ! exitif index (eve$$x_token_separators, c) > 0; ! ! If we see and "=" for the first time and we are in a DEFINE_KEY or ! an UNDEFINE_KEY command, then break the token there. Otherwise, we ! will make the = sign part of the current token. ! if (c = "=") and (not saw_equals_sign) then exitif (index ("EVE_DEFINE_KEY", eve$$x_uppercase_token) <> 0); exitif (index ("EVE_UNDEFINE_KEY", eve$$x_uppercase_token) <> 0); endif; endloop; ! ! The token is all characters from the saved original index to the current. ! return substr (eve$$x_command_line, original_index, eve$$x_command_index - original_index); endif; ! ! Process quoted strings. If the current character is a '"' or a "'", then ! eat all characters looking for either the end of the command line or the ! closing quote. ! if (c = "'") or (c = '"') then ! ! Reflect the quoted string in the state_array variable and remember what ! the opening quote character was. ! eve$$x_state_array {eve$$k_is_quoted_string} := true; quote_char := c; closed_quote := false; ! ! Loop looking for the closing quote character. Exit the loop if we have ! run out of characters. Note that closed_quote will now be false in that ! case. ! loop eve$$x_command_index := eve$$x_command_index + 1; exitif eve$$x_command_index > eve$$x_command_length; c := substr (eve$$x_command_line, eve$$x_command_index, 1); ! ! If the character is the same as the opening quote character, then ! ensure that it is not doubled ('This is '' doubled'). ! if c = quote_char then ! ! Mark the fact that we have found the closing quote. If we do ! detect that this is a doubled quote, we will reset it back to ! not having found the ending quote. ! closed_quote := true; ! ! Advance to next character exiting the loop if there are no more. ! eve$$x_command_index := eve$$x_command_index + 1; exitif eve$$x_command_index > eve$$x_command_length; c := substr (eve$$x_command_line, eve$$x_command_index, 1); ! ! Exit the loop if this is not another quote character. ! exitif c <> quote_char; ! ! This was a double quote situation. Reset the fact that we have ! not found the closing quote. ! closed_quote := false; endif; endloop; ! ! Assign this procedure either the token or add the closing quote first. ! if closed_quote then return substr (eve$$x_command_line, original_index, eve$$x_command_index - original_index); else return substr (eve$$x_command_line, original_index, eve$$x_command_index - original_index) + quote_char; endif; endif; ! ! Non-symbol, non-quoted string. Simply return the next token. ! loop exitif eve$$x_command_index > eve$$x_command_length; exitif index (eve$$x_token_separators, substr (eve$$x_command_line, eve$$x_command_index, 1)) <> 0; eve$$x_command_index := eve$$x_command_index + 1; endloop; return substr (eve$$x_command_line, original_index, eve$$x_command_index - original_index); endprocedure; ! eve$$get_token ! EVE$PARSER.TPU Page 12 procedure eve$$double_quotes ! Handle quotes in commands (string_with_quotes) ! String being processed - input ! Procedure for handling quoted string. Takes the argument, doubles ! all quotation marks, and return the resulting string. local result_string, ! Portion of string with quotes doubled rest_of_string, ! Remainder of string yet to be processed quote_index; ! Index of double-quote in rest_of_string on_error [OTHERWISE]: endon_error; result_string := ""; rest_of_string := string_with_quotes; loop quote_index := index (rest_of_string, '"'); if quote_index = 0 then result_string := result_string + rest_of_string; exitif 1; else result_string := result_string + substr (rest_of_string, 1, quote_index) + '"'; exitif quote_index = length (rest_of_string); rest_of_string := substr (rest_of_string, quote_index + 1, length (rest_of_string)); endif; endloop; return (result_string); endprocedure; ! eve$$double_quotes ! EVE$PARSER.TPU Page 13 procedure eve$$add_final_string ! Handle last command argument (result_so_far, ! String containing parse to date - input current_token) ! String containing current token - input ! Procedure for handling the last string argument in a command line ! when it is not a quoted string. Combines the current_token with all ! remaining tokens in the command line into the last argument, puts a quote ! character (" or ') before and after them, and puts a ")" on the end. ! Implicit Inputs ! eve$$x_command_line Command entered ! eve$$x_command_index Index into eve$$x_command_line while parsing ! eve$$x_command_length Length of eve$$x_command_line ! Return Value ! result_so_far + quote + current_token + rest_of_cmd_line + quote + ) local parse_result, ! Result of parsing complete command line rest_of_line, ! Remainer of command line including this token quote_mark; ! Quote mark to be used in parse_result on_error [OTHERWISE]: endon_error; parse_result := result_so_far; rest_of_line := current_token + substr (eve$$x_command_line, eve$$x_command_index, (eve$$x_command_length - eve$$x_command_index) + 1); if index (rest_of_line, '"') = 0 then quote_mark := '"'; else if index (rest_of_line, "'") = 0 then quote_mark := "'"; else ! double the quote marks in string quote_mark := '"'; rest_of_line := eve$$double_quotes (rest_of_line); endif; endif; parse_result := parse_result + quote_mark + rest_of_line + quote_mark + ")"; return (parse_result); endprocedure; ! eve$$add_final_string ! EVE$PARSER.TPU Page 14 procedure eve$$parse ! The EVE parser (line_to_parse; ! Eve command string - input prefix) ! Prefix before the procedure or variable ! name. Optional. If not specified then ! defaults to eve$$x_command_prefix and this ! procedure parses procedure names; if = "", ! then parses DECTPU builtins, otherwise, ! parses variable names. Input ! Description ! The main parsing procedure. It parses procedure names starting with ! eve$$x_command_prefix, DECTPU builtins (no prefix), or variable names ! (help informational topics) starting with a prefix passed in the optional ! second argument. ! ! General information about EVE commands: ! 1. They call procedures whose names start with "EVE_". ! For example, command SHIFT LEFT calls procedure EVE_SHIFT_LEFT. ! (Note that multi-word commands may be typed with space characters ! instead of underscores.) ! 2. They can be typed with or without parentheses to enclose arguments. ! 3. They can be typed with or without quotation marks. ! 4. They can be typed with or without arguments. Default arguments are ! provided (null string where strings are expected, eve$k_no_arg where ! integers are expected). All EVE_xxx procedures are expected to ! prompt for missing arguments. EVE allows only string and integer ! arguments for its commands. ! 5. Expected integer arguments are specified by assigning variables of ! the form eve$argN_command_name to the string "integer", where ! "N" indicates its position in the argument list for the command. ! String arguments no longer need variables, but they are accepted. ! EVE$ARG1_LINE := "integer"; ! (1st integer argument) ! EVE$ARG2_LINE := "integer"; ! (2nd integer argument) ! EVE$ARG1_SHIFT_LEFT := "integer" (only integer argument) ! 6. Commands may be subsets/supersets of other commands. The following ! are valid commands: ! SET, SET FOO, SET FOO BAR, SET FOO BAR BLETCH, ... ! 7. Commands may have tokens that are substrings of other commands' ! tokens. The following are valid commands: ! SET FOO, SET FOOS ! Overview of token processing: ! 1. Test 1st token for only symbol characters ! 2. Expand_name on (prefix + token), put into choice_buffer ! 3. Move through choice buffer looking for exact match ! 4. If not exact, search choice buffer for exact token match, ! subset token match, or substring token match. ! 5. Once have a single command, process expected arguments. ! 6. Determine how many arguments expected (eve$argN_...). ! 7. Supply default arguments for missing ones. ! 8. Handle quoted arguments ! 9. Insure argument types are either string or integer ! 10. Handle last argument ! 11. Return complete command string ! Calling sequences: EVE_DO ! cmd = "" | | cmd <> "" ! ------<-------------- ----->---- ! cur_w<>cmd_w| cur_w=cmd_w| | ! | | | ! | EVE$$ENTER_COMMAND_WINDOW | ! EVE$EXECUTE_FILE --->EVE$$EXIT_COMMAND_WINDOW | ! | | | ! --------->------------------<------------------ ! | ! EVE$PARSER_DISPATCH ! | ! EVE_HELP EVE$PROCESS_COMMAND EVE$$DEFINE_KEY ! | | | ! -------------->------------------<-------- ! | ! EVE$$PARSE ! Implicit Inputs ! eve$$x_state_array {eve$$k_is_symbol} Token only alphanumeric $ _ ! eve$$x_state_array {eve$$k_is_number} Token only numeric ! eve$$x_state_array {eve$$k_is_quoted_string} Token is a quoted string ! ! eve$$x_state_array {eve$$k_help_active} ! Flag = 1 (help) or 4 (define key) to disable ! parser error messages. If parsing variables, ! then set this so that the illegal/ambiguous ! "command" messages are not output. ! eve$argN_command_name Expected integer arguments (1...N) for a command ! Implicit Outputs ! eve$$x_command_line The input line to parse ! eve$$x_command_index Index of next character to process in command ! eve$$x_command_length Length of command line ! eve$$x_state_array {eve$$k_ambiguous_parse} ! Flag = 1 if ambiguous command ! eve$$x_uppercase_token Appended string of all tokens processed so far ! Return Value ! success: DECTPU procedure/variable string, e.g., ! procedure string = EVE_SET_LEFT_MARGIN(eve$k_no_arg), or ! variable string = EVE$KT_TOPIC_EVE_FOOBAR ! failure: null string local parse_result, ! String containing DECTPU command to execute current_token, ! String currently being processed expanded_name, ! String with all candidate commands cmd_token, ! Eve command name, with underscores cmd_name, ! Eve command name, without underscores completion, ! First possible_completion this_buffer, ! Current buffer max_args, ! Maximum arguments expected for this command all_arg_names, ! Local expand name of all arguments arg_name, ! Name of eve$argn variable arg_type, ! Argument type from eve$argN_xxx did_integer, ! Flag if processed integer arg variable original_token, ! Copy of current token (not upcased) arg_count, ! Number of argument currently being processed search_pattern, ! Pattern for token look-ahead search_range, ! Found pattern range found_string, ! Found pattern string hit_argument, ! Set if exact match found in valid cmds ! chosen before non-cmd token received the_prefix, ! Prefix for procedure/variable name the_prefix_length, ! Prefix length found_only_one, ! Set if only one command found built_pattern, ! Pattern variable curr_endtoken, curr_subtoken, prev_endtoken, prev_subtoken, current_line_text, current_line_length, uppercase_token_length, beginning_of_range, first_token_flag, ! Set if on first token underscore_index, number_of_matches, ! At least one hit in choice buffer choice_mark; ! Marker for erasing text from choice buffer on_error [TPU$_CONTROLC]: return (""); [TPU$_NONAMES, TPU$_MULTIPLENAMES]: ! trap expand_name errors [OTHERWISE]: endon_error; ! ! Default the prefix to EVE ! if prefix = tpu$k_unspecified then the_prefix := eve$$x_command_prefix; else the_prefix := prefix; endif; ! ! And compute the length of the prefix ! the_prefix_length := length (the_prefix); ! ! These three globals store the parsing state ! eve$$x_command_line := line_to_parse; eve$$x_command_index := 1; eve$$x_command_length := length (eve$$x_command_line); ! ! This is not yet an ambiguous parse ! eve$$x_state_array {eve$$k_ambiguous_parse} := FALSE; parse_result := ""; erase (eve$choice_buffer); ! ! Handle first token separately, outside the loop, for easier diagnostics ! and handling the prefix. ! eve$$x_uppercase_token := ""; original_token := eve$$get_token; ! ! If there are no tokens at all, then issue a message after inhibiting messages ! during HELP processing. ! if original_token = "" then if eve$$x_state_array {eve$$k_help_active} <> 1 then eve$message (EVE$_NOEVECMD); endif; return (""); endif; ! ! If the token is not symbol characters, then issue a message after inhibiting ! messages during HELP and DEFINE KEY processing. ! if not eve$$x_state_array {eve$$k_is_symbol} then if (eve$$x_state_array {eve$$k_help_active} <> 1) and (eve$$x_state_array {eve$$k_help_active} <> 4) then eve$message (EVE$_UNRECCMD, 0, original_token); endif; return (""); endif; ! ! Get an uppercased version of the original token into current_token ! current_token := original_token; change_case (current_token, UPPER); ! ! Get the prefix plus the uppercased token into uppercase_token ! if (index (current_token, the_prefix) = 1) then eve$$x_uppercase_token := current_token; else eve$$x_uppercase_token := the_prefix + current_token; endif; ! ! Expand the procedure or variable names based on the prefix ! case the_prefix [eve$$x_command_prefix, ""]: ! EVE commands + DECTPU builtins expanded_name := expand_name (eve$$x_uppercase_token, PROCEDURES); [INRANGE, OUTRANGE]: ! User prefixes (facility) if index (the_prefix, eve$$x_help_prefix) = 1 then ! help informational topic variables expanded_name := expand_name (eve$$x_uppercase_token, VARIABLES); else expanded_name := expand_name (eve$$x_uppercase_token, PROCEDURES); endif; endcase; ! ! If there are no matches on the expanded symbol, then issue an error message ! except during HELP and DEFINE KEY. ! if expanded_name = "" then if (eve$$x_state_array {eve$$k_help_active} <> 1) and (eve$$x_state_array {eve$$k_help_active} <> 4) then if eve$$x_state_array {eve$$k_in_init_file} then eve$message (EVE$_DONUNDERCMDINI, 0, eve$$x_current_init_cmd); else eve$message (EVE$_DONTUNDERCMD, 0, substr (eve$$x_command_line, 1, eve$$x_command_index-1)); endif; endif; return (""); endif; ! ! Place each expand_name result on a line by itself in the choice buffer. Save ! and restore the current buffer around the call. ! this_buffer := current_buffer; eve$expand_to_choices (expanded_name); position (this_buffer); ! EVE$PARSER.TPU Page 15 ! ! Initialize local variables used in the parse. ! first_token_flag := TRUE; found_only_one := FALSE; hit_argument := FALSE; completion := ""; found_string := ""; curr_endtoken := ""; curr_subtoken := ""; ! ! Loop for parsing command token. Before exiting the loop, assign parse_result ! to the partial command. Set hit_argument if next token was already fetched ! in coming up with an unambiguous command. ! loop ! ! Set up the main pattern used in this loop. ! if first_token_flag then built_pattern := eve$$x_uppercase_token; else built_pattern := built_pattern + (span (eve$x_alphanumeric_characters) | "") + ('_' + current_token); endif; ! ! Compute the search pattern ! search_pattern := built_pattern + (span (eve$x_alphanumeric_characters) | ""); ! ! Move the current subtoken/endtoken patterns into the previous variables ! and figure new ones. ! prev_subtoken := curr_subtoken; curr_subtoken := built_pattern + LINE_END; prev_endtoken := curr_endtoken; curr_endtoken := search_pattern + LINE_END; ! ! Strip all non matches out of the choices buffer. Do not do this on the ! first loop through since that first token was already used to form this ! list. ! position (eve$choice_buffer); position (buffer_begin); if first_token_flag then number_of_matches := get_info (eve$choice_buffer, "record_count"); else number_of_matches := 0; loop choice_mark := mark(none); search_range := search_quietly (search_pattern, FORWARD, EXACT); exitif search_range = 0; beginning_of_range := beginning_of (search_range); position (beginning_of_range); ! ! If it was not found at offset zero, then we want to remove this ! line also by positioning to the beginning of the next line. ! if (current_offset = 0) then number_of_matches := number_of_matches + 1; else position (line_begin); move_vertical (1); endif; if (beginning_of_range <> choice_mark) then move_horizontal (-1); erase (create_range (choice_mark, mark(none), none)); endif; move_vertical (1); endloop; if number_of_matches <> 0 then erase (create_range (choice_mark, buffer_end, none)); position (buffer_begin); endif; endif; ! EVE$PARSER.TPU Page 16 ! ! If we found no matches, then either leave the loop or return. We will ! leave the loop if we did something like eat an argument. ! if number_of_matches = 0 then ! ! If the value found_only_one is true, then we found a single hit on ! the last go round and ate an argument. ! if found_only_one then hit_argument := TRUE; exitif; endif; ! ! See if none matched because the last token was an argument ! found_string := eve$$enough_tokens (prev_endtoken, prev_subtoken); ! ! If we found the string, then we accidentally ate an argument. Set ! the hit and parse result and leave the loop. ! if found_string <> "" then hit_argument := TRUE; parse_result := found_string; exitif; endif; ! ! See if a single root EVE command is ambiguous with synonyms, and if ! so, use the root command and leave the loop. ! parse_result := eve$$parse_synonym (the_prefix); if parse_result <> 0 then hit_argument := TRUE; exitif; endif; ! ! We eliminated commands not having all tokens and have checked to make ! sure we didn't eat a parameter. Now display choices and say don't ! understand command except during HELP or DEFINE KEY. ! if (eve$$x_state_array {eve$$k_help_active} <> 4) and (eve$$x_state_array {eve$$k_help_active} <> 1) then if eve$x_executing_file then if eve$$x_state_array {eve$$k_in_init_file} then eve$message (EVE$_DONUNDERCMDINI, 0, eve$$x_current_init_cmd); else eve$message (EVE$_DONTUNDERCMD, 0, substr (eve$$x_command_line, 1, eve$$x_command_index-1)); endif; else eve$strip_choices (the_prefix_length); translate (eve$choice_buffer, " ", "_"); eve$display_choices (message_text (EVE$_DONTUNDERCMD, 0, substr (eve$$x_command_line, 1, eve$$x_command_index-1)), ""); endif; endif; position (this_buffer); return (""); endif; ! EVE$PARSER.TPU Page 17 ! ! If we matched exactly one, then determine new completion and parse_result ! from the current uppercase token. ! if number_of_matches = 1 then current_line_text := current_line; if (index (current_line_text, eve$$x_uppercase_token) <> 1) then completion := ""; else current_line_length := length (current_line_text); uppercase_token_length := length (eve$$x_uppercase_token); if current_line_length = uppercase_token_length then completion := eve$$x_uppercase_token; else underscore_index := index (substr (current_line_text, uppercase_token_length + 1, current_line_length), "_"); if underscore_index = 0 then completion := current_line_text; else completion := substr (current_line_text, 1, uppercase_token_length + underscore_index-1); endif; endif; endif; parse_result := current_line_text; if not first_token_flag then eve$$x_uppercase_token := completion + "_" + current_token; endif; found_only_one := TRUE; endif; first_token_flag := False; ! ! Get the next token. The command is still ambiguous and there are still ! tokens to be examined. ! original_token := eve$$get_token; current_token := original_token; change_case (current_token, UPPER); ! ! If there were no more tokens. ! if current_token = "" then ! ! Leave if we had a hit while processing the last token. ! exitif found_only_one; ! ! No more tokens on command line. See if the command is a subset ! or a superset of another command, or if the token is a substring ! of another commands token. ! found_string := eve$$enough_tokens (curr_endtoken, curr_subtoken); ! ! If we found the string, then we accidentally ate an argument. ! Set the hit and parse result and leave the loop. ! if found_string <> "" then parse_result := found_string; exitif; endif; ! ! See if a single root EVE command is ambiguous with synonyms, and ! if so, use the root command. ! parse_result := eve$$parse_synonym (the_prefix); ! ! Leave if we got a root command ! exitif parse_result <> 0; ! ! If we are doing builtins ! if the_prefix = "" then ! ! Eliminate all builtins from the choice buffer ! position (beginning_of (eve$choice_buffer)); loop exitif mark (NONE) = end_of (eve$choice_buffer); if get_info (PROCEDURES, "defined", current_line) then erase_line; else move_vertical (1); endif; endloop; ! ! If none are left, then leave ! if get_info (eve$choice_buffer, "record_count") = 0 then position (this_buffer); return (""); endif; endif; ! ! We eliminated commands not having all tokens. All that is left ! are ambiguous commands. ! eve$$x_state_array {eve$$k_ambiguous_parse} := TRUE; if (eve$$x_state_array {eve$$k_help_active} <> 4) and (eve$$x_state_array {eve$$k_help_active} <> 1) then if eve$x_executing_file then ! ! Display Command from file, display message only ! if eve$$x_state_array {eve$$k_in_init_file} then eve$message (EVE$_AMBCMDINIT, 0, eve$$x_current_init_cmd); else eve$message (EVE$_AMBCMD, 0, substr (eve$$x_command_line, 1, eve$$x_command_index - 1)); endif; else ! ! Display the choices on the screen ! eve$strip_choices (the_prefix_length); translate (eve$choice_buffer, " ", "_"); eve$display_choices (message_text (EVE$_AMBCMD, 0, substr (eve$$x_command_line, 1, eve$$x_command_index - 1)), ""); endif; endif; position (this_buffer); return (""); endif; endloop; ! EVE$PARSER.TPU Page 18 ! ! Position back to the main buffer. ! position (this_buffer); ! ! Convert procedure name to command (EVE_SET_LEFT_MARGIN -> set left margin) ! cmd_token := substr (parse_result, the_prefix_length + 1, 1); change_case (parse_result, LOWER); cmd_token := cmd_token + substr (parse_result, the_prefix_length + 2, length (parse_result) - (the_prefix_length + 1)); cmd_name := cmd_token; translate (cmd_name, " ", "_"); ! ! Builtins expect no arguments ! if the_prefix = "" then if get_info (PROCEDURES, "defined", parse_result) then return (""); else return (parse_result); endif; endif; ! ! Check for arguments that this command expects. Insert "" or eve$k_no_arg for ! missing string or integer arguments, respectively. ! ! How many arguments does TPU know about? ! max_args := get_info (PROCEDURES, "maximum_parameters", parse_result); ! ! Get next token (parsing command name may have completed without getting it) ! if not hit_argument then original_token := eve$$get_token; endif; ! ! Handle commands that take no arguments. ! if max_args = 0 then ! ! If we have no current token, then we are done. ! if original_token = "" then return (parse_result); endif; ! ! Complain about too many or too few arguments only when neither ! HELP nor DEFINE KEY are in use. ! if (eve$$x_state_array {eve$$k_help_active} <> 1) and (eve$$x_state_array {eve$$k_help_active} <> 4) then ! ! If we had eaten an argument and the command is ambiguous, ! then the user had entered "FOO A", but the only commands ! were "FOO B" and "FOO C". ! if (hit_argument) and (get_info (eve$choice_buffer, "record_count") > 1) then ! ! Ambiguous parse ! if eve$x_executing_file then eve$$x_state_array {eve$$k_ambiguous_parse} := TRUE; if eve$$x_state_array {eve$$k_in_init_file} then eve$message (EVE$_AMBCMDINIT, 0, eve$$x_current_init_cmd); else eve$message (EVE$_AMBCMD, 0, substr (eve$$x_command_line, 1, eve$$x_command_index - 1)); endif; else eve$strip_choices (the_prefix_length); translate (eve$choice_buffer, " ", "_"); eve$display_choices (message_text (EVE$_AMBCMD, 0, substr (eve$$x_command_line, 1, eve$$x_command_index - 1)), ""); endif; position (this_buffer); else ! ! Too many arguments ! eve$message (EVE$_TAKESNOARGS, 0, cmd_name); endif; endif; return (""); endif; ! ! Support eve$argn variables ! all_arg_names := expand_name ("EVE$ARG", VARIABLES); ! ! Set the number of arguments already processed ! arg_count := 0; ! ! Add an open paren ! parse_result := parse_result + "("; ! ! Loop to handle arguments, in 4 steps: ! ! 1) If last expected argument, check for closing punctuation ! 2) If last token, handle defaults for remaining arguments ! 3) Handle the current argument (string/integer) ! 4) Get the next token (adding "," between args in parse_result) ! loop ! ! If last argument, handle closing punctuation and return ! if arg_count = max_args then ! ! If we have no current token ! if original_token = "" then ! ! Return closed argument list ! return (parse_result + ")"); else ! ! Complain about too many or too few arguments only when neither ! HELP nor DEFINE KEY are in use. ! if (eve$$x_state_array {eve$$k_help_active} <> 1) and (eve$$x_state_array {eve$$k_help_active} <> 4) then eve$message (EVE$_TAKESONLY, 0, cmd_name, max_args); endif; return (""); endif; endif; ! ! No more tokens, add default values and return. ! if original_token = "" then ! ! Fill in the missing arguments. All EVE_ procedures must prompt ! appropriately when they get the "" or eve$k_no_arg for missing ! string or integer arguments. ! loop exitif arg_count = max_args; arg_count := arg_count + 1; did_integer := FALSE; ! ! If we have eve$arg variables ! if all_arg_names <> "" then ! ! Ensure that a valid one exists. ! arg_name := "EVE$ARG" + str (arg_count) + "_" + cmd_token; change_case (arg_name, UPPER); ! ! If we found one for this argument ! if (index (all_arg_names, arg_name) <> 0) then ! ! The value of one of these variables is STRING or INTEGER ! arg_type := execute ("return (" + arg_name + ")"); change_case (arg_type, LOWER); ! ! Give integers the value of eve$k_no_arg when not supplied ! if arg_type = "integer" then parse_result := parse_result + "eve$k_no_arg"; did_integer := TRUE; else ! ! Give an error if the value was not INTEGER or STRING ! if arg_type <> "string" then ! ! Display the message except when in DEFINE KEY ! if eve$$x_state_array {eve$$k_help_active} <> 4 then eve$message (EVE$_BADARGTYP, 0, arg_type); endif; return (""); endif; endif; endif; endif; ! ! If we had no argument variable, or if the type was string, ! then default it to a string variable. ! if not did_integer then parse_result := parse_result + '""'; endif; ! ! Add a comma if there are more arguments ! if arg_count < max_args then parse_result := parse_result + ","; endif; endloop; ! ! Add the closing paren and return ! return (parse_result + ")"); endif; ! ! Increment the argument count and set handled flag ! arg_count := arg_count + 1; did_integer := FALSE; ! ! If we have eve$arg variables ! if all_arg_names <> "" then ! ! Ensure that a valid one exists. ! arg_name := "EVE$ARG" + str (arg_count) + "_" + cmd_token; change_case (arg_name, UPPER); ! ! If we found one for this argument ! if (index (all_arg_names, arg_name) <> 0) then ! ! The value of one of these variables is STRING or INTEGER ! arg_type := execute ("return (" + arg_name + ")"); change_case (arg_type, LOWER); ! ! Give integers the value of "eve$k_no_arg" when not supplied ! if arg_type = "integer" then if eve$$x_state_array {eve$$k_is_number} then translate (original_token, "1", "l"); parse_result := parse_result + original_token; did_integer := TRUE; else ! ! Display the message except when in DEFINE KEY ! if eve$$x_state_array {eve$$k_help_active} <> 4 then eve$message (EVE$_EXPECTNUM, 0, cmd_name, arg_count); endif; return (""); endif; else ! ! Give an error if the value was not INTEGER or STRING ! if arg_type <> "string" then ! ! Display the message except when in DEFINE KEY ! if eve$$x_state_array {eve$$k_help_active} <> 4 then eve$message (EVE$_BADARGTYP, 0, arg_type); endif; return (""); endif; endif; endif; endif; ! ! If we had no argument variable, or if the type was not integer, ! then default it to a string or quoted string variable. ! if not did_integer then if eve$$x_state_array {eve$$k_is_quoted_string} then parse_result := parse_result + original_token; else ! ! Add the rest of the line if this is the last and return it ! if arg_count = max_args then return (eve$$add_final_string (parse_result, original_token)); else ! ! add quotes to the arg ! original_token := eve$$double_quotes (original_token); parse_result := parse_result + '"' + original_token + '"'; endif; endif; endif; ! ! Get next token ! original_token := eve$$get_token; ! ! Ignore user entered commas ! if original_token = "," then original_token := eve$$get_token; endif; ! ! Add commas if there are more parameters ! if arg_count < max_args then parse_result := parse_result + ","; endif; endloop; endprocedure; ! eve$$parse ! EVE$PARSER.TPU Page 19 procedure eve$$enough_tokens ! Give parser assistance (endtoken, ! pattern for end of token subtoken); ! pattern for sub token ! Determine if one of the procedure names (commands) in the choice ! buffer matches the token_end_pattern; if more than 1 do, then ! see if one matches the token_sub_pattern for the specified ! token count. ! The token_end_pattern is the normal token pattern with "+ LINE_END" ! appended to the end - for tokens that match other comand tokens that are ! sub or super sets of this command (e.g., SET, SET FOO, SET FOO BAR, ! SET FOO BAR BLETCH) ! The token_sub_pattern is the normal token pattern with the ! "+ PATTERN_TOKEN_END" removed - for tokens that are substrings ! of other command tokens (e.g., SET GRID vs SET GRIDS) ! This procedure is called when: ! 1. There are no more tokens to parse in the command line, yet ! the choice buffer contains more than one procedure name. See if ! any of them match the token_end_pattern. If none is found, ! then the ambiguous commands in choice buffer are displayed. ! If more than 1, then see if any of them match the token_sub_pattern. ! The token count has been decremented to match how many tokens ! were actually found. (token # 1 = CIRCLE in command DRAW CIRCLE) ! 2. The last token gotten (via eve$$get_token) is not part of a command, ! yet the choice buffer contains more than one procedure name. ! (The last token may be either an illegal token, or a command ! argument.) See if any of the procedures in the choice buffer ! match the token end pattern for a token count equal to 1 less ! than the last token. If none is found, then the command ! is illegal. If more than 1, then see if any of them match the ! token_sub_pattern. ! Return status ! null if no match, or procedure name matching the specified token end pattern local found_string, search_pattern, search_range, number_found, result; on_error [OTHERWISE]: endon_error; result := ""; search_pattern := endtoken; position (beginning_of (eve$choice_buffer)); loop exitif mark (NONE) = end_of (eve$choice_buffer); search_range := search_quietly (search_pattern, FORWARD, EXACT); exitif search_range = 0; position (search_range); found_string := current_line; number_found := number_found + 1; exitif number_found > 1; ! only 1 match is allowed move_vertical (1); endloop; if number_found = 1 then result := found_string; else if number_found > 1 then search_pattern := subtoken; number_found := 0; position (beginning_of (eve$choice_buffer)); loop exitif mark (NONE) = end_of (eve$choice_buffer); search_range := search_quietly (search_pattern, FORWARD, EXACT); exitif search_range = 0; position (search_range); found_string := current_line; number_found := number_found + 1; exitif number_found > 1; ! only 1 match is allowed move_vertical (1); endloop; if number_found = 1 then result := found_string; endif; endif; endif; return result; endprocedure; ! eve$$enough_tokens ! EVE$PARSER.TPU Page 20 ! EVE$CORE.T procedure eve$$parse_synonym ! Test for cmd choice = a synonym root (the_prefix) ! Test the choice buffer entries. If only one is a root in the synonym ! array, and it has a synonym, then return that root (the other ambiguous ! commands are assumed to be synonyms); otherwise, return false (there ! are ambiguous root commands). For this to work correctly, all EVE ! commands should have synonyms, not just some or most. local saved_mark, result, a_command, the_command, space_index, count; on_error [TPU$_CONTROLC]: eve$$restore_position (saved_mark); ! restore free cursor position eve$learn_abort; abort; [OTHERWISE]: eve$$restore_position (saved_mark); endon_error; if the_prefix = "" then return (FALSE); endif; saved_mark := mark (FREE_CURSOR); position (beginning_of (eve$choice_buffer)); loop exitif mark (NONE) = end_of (eve$choice_buffer); a_command := current_line; change_case (a_command, LOWER); a_command := substr (a_command, length (the_prefix) + 1, length (a_command)); ! remove EVE_ procedure prefix if eve$$x_synonym_array {a_command} <> tpu$k_unspecified then space_index := index (eve$$x_synonym_array {a_command}, " "); if space_index <> 0 then ! assume that there's a synonym count := count + 1; exitif count > 1; ! no need to go past 2 ambiguous roots the_command := current_line; endif; endif; move_vertical (1); endloop; if count = 1 then result := the_command; endif; position (saved_mark); return (result); endprocedure; ! eve$$parse_synonym ! EVE$PARSER.TPU Page 21 procedure eve$parser_dispatch ! Dispatcher for facility parsers (the_command) ! Dispatch to package specific parsers, should there be any EVE-layered ! products built in. return (eve$process_command (the_command)); endprocedure; ! eve$parser_dispatch ! EVE$PARSER.TPU Page 22 endmodule; ! ! Global constant and variable declarations ! constant eve$$x_help_prefix := "EVE$KT_TOPIC_"; ! For the parser variable eve$x_found_range, eve$x_prompt_highlighting, eve$$x_token_separators, eve$x_symbol_characters, eve$x_digit_characters, eve$x_symbol_characters, eve$x_alphanumeric_characters;