Google
 

Trailing-Edge - PDP-10 Archives - decuslib20-07 - decus/20-0172/parse3.bli
There is 1 other file named parse3.bli in the archive. Click here to see a list.
!<BLF/lowercase_user>
!<BLF/uppercase_key>
MODULE prs3 (								!

%IF %BLISS (BLISS32)
%THEN
		ADDRESSING_MODE (EXTERNAL = LONG_RELATIVE, 		!
		NONEXTERNAL = LONG_RELATIVE) ,
%FI

		IDENT = '6.3-6'
		) =
BEGIN

!++
! Facility: BLISS Formatter
!
! Abstract:
!
!	This module formats BLISS expressions, of which there
!	are two varieties: control expressions and operator
!	expressions.  'prs$expression' is the main entry point
!	to this module.  'prs$oper' formats operator expressions.
!
! Environment: transportable, with Xport
!
!
! REVISION HISTORY
!
!	15-Sep-81	TT	Permit attribute on routine formal parameters
!
!	 4-Nov-81	TT	Remove special case code in PRS$PAREN_ELIST
!				that involved routine formals list. This is now
!				handled by DO_ROUTINE_FORMALS in PARSE2.
!
! END OF REVISION HISTORY
!--

!<BLF/page>
!
! Table of contents:
!--

FORWARD ROUTINE
    do_case : NOVALUE,
    do_codecom : NOVALUE,
    do_count_loop : NOVALUE,
    do_exit : NOVALUE,
    do_if : NOVALUE,
    do_post_loop : NOVALUE,
    do_pre_loop : NOVALUE,
    do_primary : NOVALUE,
    do_select : NOVALUE,
    do_set : NOVALUE,
    prs$expression : NOVALUE,
    prs$oper : NOVALUE,
    prs$paren_elist : NOVALUE;

!
! Include files:
!--

REQUIRE 'BLFCSW';							! Defines control switches 'sw_...'

REQUIRE 'BLFMAC';						! Defines macros 'lex', 'msg', 'write'

REQUIRE 'SYMCOD';						! Defines symbol property table, 'sym...'

REQUIRE 'TOKTYP';					! Defines 'token' and the token type values 's_...'

REQUIRE 'UTLCOD';							! Defines error codes, i.e. 'er_...'

!
! Macros:
!--

!
! Equated symbols:
!--

LITERAL
    true = 1 EQL 1,
    false = 1 NEQ 1;

!
! Own storage:
!--

!
! External references:
!--

EXTERNAL ROUTINE
    ctl$switch,
    lex$getsym : NOVALUE,
    out$break : NOVALUE,
    out$cut,
    out$default : NOVALUE,
    out$erase : NOVALUE,
    out$force : NOVALUE,
    out$indent : NOVALUE,
    out$mark : NOVALUE,
    out$ntbreak : NOVALUE,
    out$pend_skip : NOVALUE,
    out$pop_marks : NOVALUE,
    out$push_marks : NOVALUE,
    out$skip : NOVALUE,
    out$space : NOVALUE,
    out$stoks : NOVALUE,
    out$tok : NOVALUE,
    do_attr_list: novalue,
    prs$block : NOVALUE,						! Parse1
    prs$plit_body : NOVALUE,						! Parse1
    scn$plit : NOVALUE,
    utl$error : NOVALUE;

EXTERNAL
    tok,
    token : tok_block,
    nolabl,						! True if labelled blocks not allowed
    symprop : sym_table;
ROUTINE do_case (block_context) : NOVALUE = 				!

!++
! Functional description:
!
!	This routine formats a CASE expression
!
! Formal parameters:
!
!	None
!
! Implicit inputs:
!
!	None
!
! Implicit outputs:
!
!	None
!
! Routine value:
!
!	None
!
! Side effects:
!
!	None
!
!--

    BEGIN
    out$tok ();								! " CASE "
    out$space (1);
    lex;
    prs$expression (.block_context);

    IF .tok EQL s_from
    THEN
	BEGIN
	out$stoks ();							! " FROM "
	lex;
	prs$expression (.block_context);

	IF .tok EQL s_to
	THEN
	    BEGIN
	    out$stoks ();						! " TO "
	    lex;
	    prs$expression (.block_context);				! Limit expression

	    IF .tok EQL s_of
	    THEN
		(out$stoks (); out$force (); lex; )			! "OF"
	    ELSE
		utl$error (er_of);

	    IF .tok EQL s_set
	    THEN
		BEGIN
		out$indent (1);
		do_set (.block_context);
		END
	    ELSE
		utl$error (er_set);					!"SET..TES" missing.

	    IF .tok EQL s_tes
	    THEN
		BEGIN
		out$break ();
		out$tok ();						! Output the "TES"
		out$indent (-1);
		lex;
		END
	    ELSE
		utl$error (er_tes);

	    END;

	END
    ELSE
	utl$error (er_from);

    END;								! End of routine 'do_case'
ROUTINE do_codecom (block_context) : NOVALUE = 				!

!++
! Functional description:
!
!	This routine formats a CODECOMMENT
!
! Formal parameters:
!
!	None
!
! Implicit inputs:
!
!	None
!
! Implicit outputs:
!
!	None
!
! Routine value:
!
!	None
!
! Side effects:
!
!	None
!
!--

    BEGIN
    out$break ();
    out$tok ();								! "CODECOMMENT"
    lex;

    WHILE .tok NEQ s_end_of_file DO
	BEGIN

	IF .tok EQL s_string
	THEN
	    BEGIN
	    out$break ();
	    out$tok ();							! String specified
	    lex;
	    END
	ELSE
	    utl$error (er_string);

	IF .tok EQL s_comma
	THEN
	    BEGIN
	    out$erase ();
	    out$tok ();							! ","
	    lex;
	    END
	ELSE
	    BEGIN

	    IF .tok EQL s_colon
	    THEN
		BEGIN
		out$stoks ();						! " : "
		lex;
		END
	    ELSE
		utl$error (er_colon);

	    EXITLOOP;
	    END;

	END;

    IF .tok EQL s_begin OR .tok EQL s_lparen THEN prs$block () ELSE utl$error (er_block_start);

    END;								! End of routine 'do_codecomment'
ROUTINE do_count_loop (block_context) : NOVALUE = 			!

!++
! Functional description:
!
!	This routine formats INCR and DECR loops
!
! Formal parameters:
!
!	None
!
! Implicit inputs:
!
!	None
!
! Implicit outputs:
!
!	None
!
! Routine value:
!
!	None
!
! Side effects:
!
!	None
!
!--

    BEGIN
    out$tok ();								! " INCR " or " DECR "
    out$space (1);
    lex;
    out$indent (1);							! Prepare for following lines

    IF .tok EQL s_name
    THEN
	BEGIN
	out$tok ();							! Name of index variable
	lex;
	END
    ELSE
	utl$error (er_name);

    WHILE .tok EQL s_from						!
	OR .tok EQL s_to						!
	OR .tok EQL s_by DO
	BEGIN
	out$stoks ();							! " FROM ", " TO ", or " BY "
	lex;
	prs$expression (.block_context);
	END;

    IF .tok EQL s_do
    THEN
	BEGIN
	out$stoks ();							! " DO " appears on the same line
	(IF .block_context NEQ s_lparen THEN out$force ());
	lex;
	END
    ELSE
	utl$error (er_do);

    out$indent (-1);
    prs$expression (.block_context);					! Parse the action expression.
    END;								! End of routine 'do_count_loop'
ROUTINE do_exit (block_context) : NOVALUE = 				!

!++
! Functional description:
!
!	This routine formats LEAVE, RETURN, and EXITLOOP expressions
!
! Formal parameters:
!
!	None
!
! Implicit inputs:
!
!	None
!
! Implicit outputs:
!
!	None
!
! Routine value:
!
!	None
!
! Side effects:
!
!	None
!
!--

    BEGIN

    IF .tok EQL s_leave
    THEN
	BEGIN
	out$tok ();							! " LEAVE "
	out$space (1);
	lex;
	out$tok ();							! <label>
	lex;

	IF .tok NEQ s_with THEN RETURN;

	END;

    out$tok ();								! " RETURN " or " EXITLOOP "
    out$space (1);
    lex;
    prs$expression (.block_context);
    END;								! End of routine 'do_exit'
ROUTINE do_if (block_context) : NOVALUE = 				!

!++
! Functional description:
!
!	This routine formats an IF expression
!
! Formal parameters:
!
!	None
!
! Implicit inputs:
!
!	None
!
! Implicit outputs:
!
!	None
!
! Routine value:
!
!	None
!
! Side effects:
!
!	None
!
!--

    BEGIN
    out$push_marks ();
    out$tok ();								! " IF "
    out$space (1);
    lex;
    prs$expression (.block_context);				! Parse the control conditional expr.

    IF .tok EQL s_then
    THEN
	BEGIN

	IF .block_context NEQ s_lparen
	THEN

	    IF out$cut ()
	    THEN
		out$break ()						! On a new line put
	    ELSE
		BEGIN
		out$space ();
		out$mark (0);
		out$mark (0);
		END;

	out$stoks ();							! "THEN "

	IF .block_context NEQ s_lparen
	THEN

	    IF out$cut ()
	    THEN
		out$force ()
	    ELSE
		BEGIN
		out$space ();
		out$mark (1);
		END;

	lex;
	prs$expression (.block_context);			! Parse the 'true' action expression.

	IF .tok EQL s_else
	THEN
	    BEGIN

	    IF .block_context NEQ s_lparen
	    THEN

		IF out$cut ()
		THEN
		    out$break ()					! On another new line put
		ELSE
		    BEGIN
		    out$space ();
		    out$mark (0);
		    out$mark (0);
		    END;

	    out$stoks ();						! "ELSE "

	    IF .block_context NEQ s_lparen
	    THEN

		IF out$cut ()
		THEN
		    out$force ()
		ELSE
		    BEGIN
		    out$space ();
		    out$mark (1);
		    END;

	    lex;
	    prs$expression (.block_context);				! Parse the 'false' action expr.
	    END;

	END
    ELSE
	utl$error (er_then);

    out$pop_marks ();
    END;								! End of routine 'do_if'
ROUTINE do_post_loop (block_context) : NOVALUE = 			!

!++
! Functional description:
!
!	This routine formats DO-WHILE and DO-UNTIL expressions
!
! Formal parameters:
!
!	None
!
! Implicit inputs:
!
!	None
!
! Implicit outputs:
!
!	None
!
! Routine value:
!
!	None
!
! Side effects:
!
!	None
!
!--

    BEGIN
    out$tok ();								! " DO "
    out$force ();
    lex;
    prs$expression (.block_context);					! Parse the action expression

    IF .tok EQL s_while OR .tok EQL s_until
    THEN
	BEGIN
	out$break ();							! Put the terminating
	out$tok ();							! "UNTIL " or "WHILE " on new line
	out$space (1);
	lex;
	prs$expression (.block_context);				! Conditional for loop
	END
    ELSE
	utl$error (er_post_test);					! "UNTIL" or "WHILE" missing.

    END;								! End of routine 'do_post_loop'
ROUTINE do_pre_loop (block_context) : NOVALUE = 			!

!++
! Functional description:
!
!	This routine formats WHILE and UNTIL expressions
!
! Formal parameters:
!
!	None
!
! Implicit inputs:
!
!	None
!
! Implicit outputs:
!
!	None
!
! Routine value:
!
!	None
!
! Side effects:
!
!	None
!
!--

    BEGIN
    out$tok ();								! " UNTIL " or " WHILE "
    out$space (1);
    lex;
    prs$expression (.block_context);					! Conditional value for loop

    IF .tok EQL s_do
    THEN
	BEGIN
	out$stoks ();							! ' DO ' appears on same line

	IF .block_context NEQ s_lparen THEN out$force ();

	lex
	END
    ELSE
	utl$error (er_do);

    prs$expression (.block_context);					! Parse the action expression
    END;								! End of  routine 'do_pre_loop'
ROUTINE do_primary (block_context) : NOVALUE = 				!

!++
! Functional description:
!
!	This routine formats primaries.
!	Since a routine call is a primary, and since a routine
!	address in a routine call is a primary, we continue
!	searching for a "(" after we have found a primary,
!	and continue until there are no more routine calls.
!
!	For the purposes of the formatter, "REP expr OF (list)"
!	is regarded as a primary. This provides for a simple means
!	of handling PLIT bodies and also the argument lists for calls
!	to CH$TRANSTABLE.
!
! Formal parameters:
!
!	None
!
! Implicit inputs:
!
!	None
!
! Implicit outputs:
!
!	None
!
! Routine value:
!
!	None
!
! Side effects:
!
!	None
!
!--

    BEGIN

    !+
    ! Primaries are parsed at the highest precedence level
    !-

    IF .symprop [.tok, sym_close_br] THEN RETURN;

    SELECTONE .tok OF
	SET

	[s_numeric, s_string] :
	    BEGIN
	    out$tok ();							! "Numeric" or "string"
	    lex;
	    END;

	[s_begin, s_lparen] :
	    prs$block ();

	[s_langle, s_lbracket] :

	    !+
	    ! To handle keyword macro refs...
	    !-

	    prs$paren_elist (.block_context);

	[s_plit, s_uplit] :
	    BEGIN
	    out$tok ();							! "PLIT " or "UPLIT "
	    out$space ();

	    IF NOT ctl$switch (sw_plit) THEN scn$plit (+1);		! Suppress formatting of PLIT-bodies

	    lex;
	    prs$plit_body (.block_context);

	    IF NOT ctl$switch (sw_plit) THEN scn$plit (-1);

	    END;

	[s_rep] :
	    BEGIN
	    out$stoks ();
	    lex;
	    prs$expression (.block_context);

	    IF .tok NEQ s_of THEN utl$error (er_of);

	    out$default ();
	    lex;

	    IF .symprop [.tok, sym_type] EQL alloc_unit THEN (out$tok (); lex; );

	    prs$paren_elist (.block_context);
	    END;

	[s_codecomment] :
	    do_codecom (.block_context);

	[s_name] :
	    BEGIN

	    !+
	    ! The following test is heuristic: if the expected colon is one
	    ! space beyond the current name, we can pre-recognize it as a
	    ! label and left-adjust the label on a new line.
	    !-

	    IF CH$RCHAR (CH$PLUS (.token [tok_cp], .token [tok_len])) EQL %C' ' AND 	!
		CH$RCHAR (CH$PLUS (.token [tok_cp], .token [tok_len] + 1)) EQL %C':' AND 	!
		NOT .nolabl
	    THEN
		out$ntbreak ();						! Left- adjust label on new line

	    out$tok ();							! name
	    lex;

	    IF .tok EQL s_string
	    THEN
		(out$tok (); lex; )					! "String"
	    ELSE

		IF .tok EQL s_colon AND NOT .nolabl
		THEN
		    BEGIN
		    out$stoks ();					! " : "
		    out$force ();
		    lex;
		    prs$block ();
		    END;

	    END;



	[OTHERWISE] : 							! Check for allocation-unit
	    BEGIN
!	    IF .symprop [.tok, sym_type] NEQ alloc_unit
!	    THEN
!		utl$error (er_primary);
	    out$default ();						! "BYTE", e.g.
	    lex;
	    END;
	TES;

    WHILE .symprop [.tok, sym_type] EQL open_bracket DO
	prs$paren_elist (.block_context);

    END;								! End of routine 'do_primary'
ROUTINE do_select (block_context) : NOVALUE = 				!

!++
! Functional description:
!
!	This routine formats SELECT, SELECTONE, etc. expressions
!
! Formal parameters:
!
!	None
!
! Implicit inputs:
!
!	None
!
! Implicit outputs:
!
!	None
!
! Routine value:
!
!	None
!
! Side effects:
!
!	None
!
!--

    BEGIN
    out$tok ();								! " SELECT... "
    out$space (1);
    lex;
    prs$expression (.block_context);

    IF .tok EQL s_of
    THEN
	BEGIN
	out$stoks ();							! " OF "
	out$force ();
	lex;
	END
    ELSE
	utl$error (er_of);

    IF .tok EQL s_set THEN (out$indent (1); do_set (.block_context); ) ELSE utl$error (er_set);

    IF .tok EQL s_tes
    THEN
	BEGIN
	out$break ();
	out$tok ();							! "TES"
	out$indent (-1);
	lex;
	END
    ELSE
	utl$error (er_tes);

    END;								! End of routine 'do_select'
ROUTINE do_set (block_context) : NOVALUE = 				!

!++
! Functional description:
!
!	This  routine is called to format the SET..TES in
!	CASE and SELECT expressions.
!
! Formal parameters:
!
!	None
!
! Implicit inputs:
!
!	None
!
! Implicit outputs:
!
!	None
!
! Routine value:
!
!	None
!
! Side effects:
!
!	None
!
!--

    BEGIN

    IF .block_context NEQ s_lparen THEN out$break ();			! On a new line put the

    out$stoks ();							! "SET"
    out$force ();
    lex;

    WHILE .tok EQL s_lbracket DO
	BEGIN

	IF .block_context NEQ s_lparen THEN out$skip (1);

	out$tok ();							! "["
	lex;

	WHILE .tok NEQ s_end_of_file DO
	    BEGIN

	    !+
	    ! [ Label ,... ]
	    !-

	    prs$expression (.block_context);

	    IF .tok EQL s_to						! " TO " <expr>
	    THEN
		(out$stoks (); lex; prs$expression (.block_context); );

	    IF .tok EQL s_rbracket
	    THEN
		BEGIN
		out$tok ();						! Closing bracket
		lex;
		EXITLOOP;
		END;

	    IF .tok EQL s_comma
	    THEN
		BEGIN
		out$erase ();
		out$tok ();						! ", "
		out$space (1);
		lex;
		END
	    ELSE

		IF .tok EQL s_tes THEN RETURN ELSE (utl$error (er_set_tes); out$default (); lex; );

	    END;							! [ Label ,... ]

	IF .tok EQL s_colon
	THEN
	    BEGIN
	    out$stoks ();						! " : "

	    IF .block_context NEQ s_lparen THEN out$force ();

	    out$indent (+1);					! Indent block comments at head of block
	    lex;
	    out$indent (-1);
	    END
	ELSE
	    utl$error (er_colon);

	prs$expression (.block_context);				! Action for this value of the set

	IF .tok EQL s_semicolon
	THEN
	    BEGIN
	    out$erase ();
	    out$tok ();							! ";"
	    out$force ();
	    lex;
	    END;

	END;

    END;								! End of routine 'do_set'
GLOBAL ROUTINE prs$expression (block_context) : NOVALUE = 		!

!++
! Functional description:
!
!	This routine formats expressions.
!
! Formal parameters:
!
!	None
!
! Implicit inputs:
!
!	None
!
! Implicit outputs:
!
!	None
!
! Routine value:
!
!	None
!
! Side effects:
!
!	None
!
!--

    BEGIN

    LOCAL
	save_tok;

    out$indent (1);							! Always for every expr.

    IF .tok LSS first_control						!
	OR .tok GTR last_control
    THEN
	prs$oper (1, .block_context)					! Operator expression
    ELSE 								! It's a control expression.
	BEGIN

	!+
	! Dispatch through a transfer vector to format a
	! Control expression .  The format of this vector depends
	! On the ordering of the control symbols in 'TOKTYP.BLI'.
	!-

	BIND
	    ctl_routines = 						!
		UPLIT (
		do_if, 							!
		do_case, 						!
		REP 6 OF (do_select), 					!
		REP 6 OF (do_count_loop), 				!
		REP 2 OF (do_pre_loop), 				!
		do_post_loop, 						!
		REP 3 OF (do_exit))					!
	    : VECTOR [last_control - first_control + 1];

	save_tok = .tok;

	IF .tok LSS s_leave AND 					!
	    .block_context NEQ s_lparen
	THEN
	    out$skip (1);

	! Skip a line for non-trivial control
									! Expressions
	(.ctl_routines [.tok - first_control]) (.block_context);

	!+
	! Skip a line after each non-trivial control expression
	!-

	IF .save_tok LSS s_leave AND 					!
	    .block_context NEQ s_lparen
	THEN
	    out$pend_skip (1);

	END;

    out$indent (-1);
    RETURN;
    END;								! End of routine 'prs$expression'
GLOBAL ROUTINE prs$oper (level, block_context) : NOVALUE = 		!

!++
! Functional description:
!
!	This routine is called to format all operator expressions.
!
!	These are:
!
!	E1 ::= E2 = E1 \ E2
!	E2 ::= E3 EQV E2 \ E3
!		  XOR
!	E3 ::= E4 OR E3 \ E4
!	E4 ::= E5 AND E4 \ E5
!	E5 ::= NOT E5 \ E6
!	E6 ::= E7 <Relational-operators> E7 \ E7
!	E7 ::= E8 + E7 \ E8
!		  -
!	E8 ::= E9 * E8 \ E9
!		  /
!		  MOD
!	E9 ::= E10 ^ E9 \ E10
!	E10 ::= + E11
!		-
!	E11 ::= . E11 \ PRIMARY
!
!	Note that the precedence level of a PRIMARY is 12.
!
! Formal parameters:
!
!	Level - the precedence level this call is to parse at.
!
! Implicit inputs:
!
!	None
!
! Implicit outputs:
!
!	None
!
! Routine value:
!
!	None
!
! Side effects:
!
!	None
!
!--

!<BLF/page>
    BEGIN

    LOCAL
	num_choice;

    MACRO
	plit_count (aplit) =

		((aplit)-%UPVAL)%;

    BIND
	BINARY = UPLIT (0, REP 4 OF (true), false, REP 4 OF (true),
	    false, false) : VECTOR,
	right_prece = 							!
	    UPLIT (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) : VECTOR,
	left_prece = 							!
	    UPLIT (0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12) : VECTOR,	! No left precedence for unary ops
	prece_tokens = 							!
	    UPLIT (
	    0, 								! Levels
	    PLIT(s_equal), 						! 1
	    PLIT(s_eqv, s_xor), 					! 2
	    PLIT(s_or), 						! 3
	    PLIT(s_and), 						! 4
	    PLIT(s_not), 						! 5
	    PLIT(							!
	    s_eql, 							! 6
	    s_neq, 							! 6
	    s_lss, 							! 6
	    s_leq, 							! 6
	    s_gtr, 							! 6
	    s_geq, 							! 6
	    s_eqlu, 							! 6
	    s_nequ, 							! 6
	    s_lssu, 							! 6
	    s_lequ, 							! 6
	    s_gtru, 							! 6
	    s_gequ, 							! 6
	    s_eqla, 							! 6
	    s_neqa, 							! 6
	    s_lssa, 							! 6
	    s_leqa, 							! 6
	    s_gtra, 							! 6
	    s_geqa), 							! 6
	    PLIT(s_plus, s_minus), 					! 7
	    PLIT(s_multiply, s_divide, s_mod), 				! 8
	    PLIT(s_circumflex), 					! 9
	    PLIT(s_plus, s_minus), 					! 10
	    PLIT(s_dot))						! 11
	: VECTOR;

    BIND
	choice = .prece_tokens [.level] : VECTOR;

    LITERAL
	primary_level = 12;

!<BLF/page>
    IF .symprop [.tok, sym_close_br] THEN RETURN;

    IF .level EQL primary_level THEN (do_primary (.block_context); RETURN; );

    !+
    ! If binary level, try for left operand. Check operator.
    ! If it matches, try for right operand, and return.
    ! If unary, try to match operator.
    ! If it matches, try for right operand and return.
    ! Otherwise, try for a left operand and return.
    !-

    IF .BINARY [.level] THEN prs$oper (.left_prece [.level], .block_context);

    num_choice = .plit_count (choice);

    INCR i FROM 0 TO .num_choice - 1 DO
	BEGIN

	IF .tok EQL .choice [.i]
	THEN
	    BEGIN

	    IF .tok EQL s_dot OR 					!
		.tok EQL s_multiply OR 					!
		.tok EQL s_divide OR 					!
		.tok EQL s_circumflex OR 				!
		.level EQL 10 AND 					!
		(.tok EQL s_plus OR .tok EQL s_minus)			! Unary +,-
	    THEN
		out$tok ()						! ".", "*", or "/"
	    ELSE
		out$stoks ();						! Binary "+", "-", etc.

	    lex;
	    prs$oper (.right_prece [.level], .block_context);
	    RETURN;
	    END;

	END;

    IF NOT .BINARY [.level] THEN prs$oper (.left_prece [.level], .block_context);

    RETURN;
    END;								! End of routine 'prs$oper'
GLOBAL ROUTINE prs$paren_elist (block_context) : NOVALUE = 		!

!++
! Functional description:
!
!	This routine is invoked to parse a list of expressions,
!	ending with the close bracket corresponding to
!	the symbol contained in 'token', which is
!	assumed to contain the left bracket of the list to
!	be parsed.
!
! Formal parameters:
!
!	None
!
! Implicit inputs:
!
!	None
!
! Implicit outputs:
!
!	None
!
! Routine value:
!
!	None
!
! Side effects:
!
!	None
!
!--

    BEGIN

    LOCAL
	bracket;							! Which kind of bracket opened it

    BIND
	kinds = UPLIT (s_lparen, s_langle, s_lbracket) : VECTOR,
	match = UPLIT (s_rparen, s_rangle, s_rbracket) : VECTOR;

    bracket = .tok;
    out$push_marks ();

    IF .tok NEQ s_langle THEN out$space (1);

    out$tok ();								! Output the left symbol
    lex;

    WHILE .tok NEQ s_end_of_file DO
	BEGIN
	prs$expression (.block_context);

	IF .tok EQL s_comma OR 						!
	    .tok EQL s_semicolon					! In general structure references
	THEN
	    BEGIN
	    out$erase ();
	    out$tok ();							! ", " or "; "
	    out$space (1);
	    out$pop_marks ();
	    out$push_marks ();
	    out$mark (1);						! Prepare to break line here
	    lex;
	    END
	ELSE
	    EXITLOOP;

	END;

								! TT  4-Nov-81
    INCR i FROM 0 TO 2 DO

	IF .kinds [.i] EQL .bracket
	THEN
	    BEGIN

	    IF .tok NEQ .match [.i]
	    THEN
		utl$error (er_inv_bracket)
	    ELSE
		BEGIN
		out$tok ();						! Closing bracket
		out$pop_marks ();
		out$push_marks ();
		lex;
		END;

	    EXITLOOP;
	    END;

    out$pop_marks ();
    END;								! End of routine 'prs$paren_elist'
%TITLE 'Last page of PARSE3.BLI'
END									! End of module 'PARSE3'

ELUDOM