?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE SCL Interpreter : Parse Command' ??
MODULE clm$parse_command;

{
{ PURPOSE:
{   This module contains the routines that parse a command image.
{

?? NEWTITLE := 'Global Declarations', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc clc$lexical_units_size_pad
*copyc cle$ecc_command_processing
*copyc cle$ecc_file_reference
*copyc cle$ecc_lexical
*copyc cle$ecc_parsing
*IF $true(osv$unix)
*copyc cle$not_supported
*IFEND
*copyc clt$command_line
*copyc clt$command_line_index
*copyc clt$command_line_size
*copyc clt$command_list
*copyc clt$command_reference_form
*copyc clt$file
*copyc clt$lexical_unit_kind
*copyc clt$name
*copyc clt$parse_state
*copyc clt$utility_name
*copyc ost$name
*copyc ost$status
?? POP ??
*copyc clp$append_status_parse_state
*copyc clp$evaluate_command_reference
*copyc clp$get_work_area
*copyc clp$identify_lexical_units
*copyc clp$initialize_parse_state
*copyc clp$scan_any_lexical_unit
*copyc clp$scan_non_space_lexical_unit
*copyc clp$scan_unnested_rel_lex_unit
*copyc clp$trimmed_string_size
*copyc osp$set_status_abnormal
*copyc osv$lower_to_upper

?? TITLE := 'clp$parse_command', EJECT ??
*copyc clh$parse_command

  PROCEDURE [XDCL, #GATE] clp$parse_command
    (VAR parse {input, output} : clt$parse_state;
     VAR prompting_requested: boolean;
     VAR escaped: boolean;
     VAR label: ost$name;
     VAR command_reference_parse: clt$parse_state;
     VAR file: clt$file;
     VAR form: clt$command_reference_form;
     VAR name: clt$name;
     VAR utility_command_list_entry: ^clt$command_list_entry;
     VAR separator: clt$lexical_unit_kind;
     VAR empty_command: boolean;
     VAR status: ost$status);

    VAR
      command_reference: clt$command_reference,
      command_reference_size: clt$command_line_size,
      local_parse: clt$parse_state,
      parameter_name: clt$parameter_name,
      space_needed_after_colon: boolean,
      work_area: ^^clt$work_area;


    status.normal := TRUE;

    IF parse.unit_is_space THEN
      clp$scan_non_space_lexical_unit (parse);
    IFEND;

    CASE parse.unit.kind OF
    = clc$lex_query =
      prompting_requested := TRUE;
      clp$scan_non_space_lexical_unit (parse);
      escaped := parse.unit.kind = clc$lex_divide;
      IF escaped THEN
        clp$scan_non_space_lexical_unit (parse);
      IFEND;
    = clc$lex_divide =
      prompting_requested := FALSE;
      escaped := TRUE;
      clp$scan_non_space_lexical_unit (parse);
    = clc$lex_end_of_line, clc$lex_semicolon =
      empty_command := TRUE;
      RETURN;
    ELSE
      prompting_requested := FALSE;
      escaped := FALSE;
    CASEND;
    empty_command := FALSE;
    form := clc$name_only_command_ref;
    utility_command_list_entry := NIL;

    label := osc$null_name;
    command_reference_parse := parse;
    IF parse.unit.kind = clc$lex_name THEN
      clp$scan_non_space_lexical_unit (parse);
      IF parse.unit.kind = clc$lex_colon THEN
        #TRANSLATE (osv$lower_to_upper, parse.text^ (parse.previous_non_space_unit_index,
              parse.previous_non_space_unit.size), label);
        space_needed_after_colon := parse.previous_unit_is_space;
        clp$scan_non_space_lexical_unit (parse);
        IF parse.previous_unit_is_space OR (NOT space_needed_after_colon) THEN
          command_reference_parse := parse;
        ELSE
          label := osc$null_name;
          parse := command_reference_parse;
        IFEND;
      ELSE
        parse := command_reference_parse;
      IFEND;
    IFEND;

    IF parse.unit.kind = clc$lex_long_name THEN
      osp$set_status_abnormal ('CL', cle$name_too_long, parse.text^ (parse.unit_index, parse.unit.size),
            status);
      RETURN;
    IFEND;

    IF parse.unit.kind = clc$lex_equal THEN
      command_reference_parse.index_limit := parse.unit_index;
      command_reference_size := 0;
      separator := clc$lex_equal;
    ELSE
      clp$scan_unnested_rel_lex_unit (parse);
      command_reference_parse.index_limit := parse.unit_index;
      command_reference_size := parse.unit_index - command_reference_parse.unit_index;
      IF parse.unit_is_space THEN
        clp$scan_non_space_lexical_unit (parse);
      IFEND;
      CASE parse.unit.kind OF
      = clc$lex_equal, clc$lex_comma, clc$lex_end_of_line, clc$lex_semicolon =
        separator := parse.unit.kind;
        clp$scan_non_space_lexical_unit (parse);
      ELSE
        IF NOT parse.previous_unit_is_space THEN
          osp$set_status_abnormal ('CL', cle$unexpected_after_command, '', status);
          clp$append_status_parse_state (osc$status_parameter_delimiter, parse, status);
          RETURN;
        IFEND;
        separator := clc$lex_space;
      CASEND;
    IFEND;

    IF separator = clc$lex_equal THEN
      IF command_reference_size = 0 THEN
        name.value := 'CASE selection';
        name.size := 14 { STRLENGTH('CASE selection') } ;
      ELSE
        name.value := 'assignment';
        name.size := 10 { STRLENGTH('assignment') } ;
      IFEND;
      RETURN;
    IFEND;

    local_parse := command_reference_parse;
    CASE local_parse.unit.kind OF
    = clc$lex_colon, clc$lex_dot =
      ;
    = clc$lex_name =
      clp$scan_any_lexical_unit (local_parse);
      IF local_parse.unit_index = local_parse.index_limit THEN
        #TRANSLATE (osv$lower_to_upper, local_parse.text^ (local_parse.previous_non_space_unit_index,
              local_parse.previous_non_space_unit.size), name.value);
        name.size := local_parse.previous_non_space_unit.size;
        RETURN;
      IFEND;
    ELSE
*IF $true(osv$unix)
      IF local_parse.text^ (local_parse.unit_index, 1) = '!' THEN
        osp$set_status_abnormal ('CL', cle$epix_command_requested, '', status);
      ELSE
*IFEND
      osp$set_status_abnormal ('CL', cle$expecting_command, local_parse.
            text^ (local_parse.unit_index, command_reference_size), status);
*IF $true(osv$unix)
      IFEND;
*IFEND
      RETURN;
    CASEND;

    local_parse := command_reference_parse;
*IF NOT $true(osv$unix)
    clp$get_work_area (#RING (^work_area), work_area, status);
*ELSE
    clp$get_work_area (osc$user_ring, work_area, status);
*IFEND
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    clp$evaluate_command_reference (local_parse, work_area^, TRUE, file.local_file_name, command_reference,
          utility_command_list_entry, parameter_name, status);
    IF status.normal THEN
      IF parameter_name <> osc$null_name THEN
        osp$set_status_abnormal ('CL', cle$parameter_never_given_value, parameter_name, status);
        RETURN;
      IFEND;
      IF local_parse.unit_index <> local_parse.index_limit THEN
        osp$set_status_abnormal ('CL', cle$unexpected_after_command, '', status);
        clp$append_status_parse_state (osc$status_parameter_delimiter, local_parse, status);
      IFEND;
      form := command_reference.form;
      name.size := clp$trimmed_string_size (command_reference.name);
      name.value := command_reference.name;
*IF $true(osv$unix)
      IF status.normal AND (form <> clc$name_only_command_ref) THEN
        osp$set_status_abnormal ('CL', cle$not_supported,
              'FILE_CYCLE, SYSTEM, UTILITY, and MODULE_OR_FILE command references are', status);
      IFEND;
*IFEND
    ELSEIF status.condition = cle$expecting_file_reference THEN
      status.condition := cle$expecting_command;
    IFEND;

  PROCEND clp$parse_command;
*IF NOT $true(osv$unix)
?? TITLE := 'clp$analyze_command', EJECT ??
*copyc clh$analyze_command

  PROCEDURE [XDCL, #GATE] clp$analyze_command
    (    command_text: ^clt$command_line;
     VAR prompting_requested: boolean;
     VAR escaped: boolean;
     VAR label: ost$name;
     VAR command_reference_index: clt$command_line_index;
     VAR command_reference_size: clt$command_line_size;
     VAR file: clt$file;
     VAR form: clt$command_reference_form;
     VAR name: clt$name;
     VAR utility_name: clt$utility_name;
     VAR parameter_list_index: clt$command_line_index;
     VAR separator: clt$lexical_unit_kind;
     VAR empty_command: boolean;
     VAR status: ost$status);

    VAR
      command_reference_parse: clt$parse_state,
      lexical_units: ^clt$lexical_units,
      lexical_work_area: ^clt$work_area,
      parse: clt$parse_state,
      utility_command_list_entry: ^clt$command_list_entry;


    status.normal := TRUE;

    PUSH lexical_work_area: [[REP STRLENGTH (command_text^) + clc$lexical_units_size_pad OF
          clt$lexical_unit]];

    clp$identify_lexical_units (command_text, lexical_work_area, lexical_units, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    clp$initialize_parse_state (command_text, lexical_units, parse);
    clp$scan_any_lexical_unit (parse);

    clp$parse_command (parse, prompting_requested, escaped, label, command_reference_parse, file, form, name,
          utility_command_list_entry, separator, empty_command, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    IF NOT empty_command THEN
      command_reference_index := command_reference_parse.unit_index;
      command_reference_size := command_reference_parse.index_limit - command_reference_parse.unit_index;
      IF utility_command_list_entry <> NIL THEN
        utility_name := utility_command_list_entry^.utility_name;
      ELSE
        utility_name := osc$null_name;
      IFEND;
      parameter_list_index := parse.unit_index;
    IFEND;

  PROCEND clp$analyze_command;
*IFEND

MODEND clm$parse_command;
