%{

#include "parstree.c" 					/* all parstree-building routines */

#define YYMAXDEPTH			256

extern int yylex(void);
static void yyerror(char*);

expr progval;
%}

%start enclosed_clause

%union { modept mode; mlist ml; struct applnode tag; short monop; int n;
	mi_type mi; prinode std; structnode port; op_type op;
	act_mode act; act_port aprt; act_rower arwr;
	expr exp; expr* expo; elisp elis; series ser; conflisp cnfl; f_info form;
	dexlist dex; idopdecls idop; vardec var; inxlisp inx;
	collist coll; insertion ins; ins_rep insr; picture pict;
	framelist frms; frames_ins frins; littlist litl;
}

%token
	BEG 1 END 2 MODE 3 PRIO 4 OP 5 EXIT 6 PAR 7
	IF 8 THEN 9 ELSE 10 ELIF 11 FI 12 CASE 13 IN 14 OUT 15 OUSE 16 ESAC 17
	FOR 18 FROM 19 BY 20 TO 21 WHILE 22 DO 23 OD 24
	OF 25 AT 26 SKIP 27 NIL 28 GOTO 29
	REF 30 FLEX 31 STRUCT 32 PROC 33 UNION 34 
	BECOMES 35 AGAIN 36 LPAR 37 RPAR 38 SUB 39 BUS 40
	COMMA 41 SEMIC 42 COLON 43 BAR 44 DOLLAR 45
%token <op>  EQUALS 46 TILDE 47
%token <n>   LEAP 48 RELATOR 49
%token <tag> TAG 50
%token <mi>  MODE_INDICATION 51
%token <std> STANDARD 52
%token <op>  OPERATOR 53 DYOP 54
%token <exp> DENOTATION 55 
%token       Z 56 SZ 57
%token <n>   ASA 58 DSD 59 ESE 60 ISI 61 PSPOINT 62 PLM 63 ALIGNMENT_CODE 64
%token       N 65 C 66 B 67 F 68 G 69
%token <monop> LITT 70 REP 71
%token <n>   RADIX 72

%type <op>			operator
%type <monop>		monadic_operator for_opt
%type <act> 		actual_declarer actuol_declarer actmal_declarer
%type <mode>		formal_declarer virtual_declarer formol_declarer
%type <ml>			joined_declarer
%type <arwr>		actual_rower
%type <n> 			formal_rower
%type <aprt>		actuol_portrait actuol_portrait_tail
								actmal_portrait actmal_portrait_tail
%type <port>		formol_portrait formol_portrait_tail
								virtual_portrait virtual_portrait_tail
								parameters param_tail
%type <ser> 		series enquiry_clause while_opt label_series
%type <exp> 		enclosed_clause primary secondary tertiary unit
								closed_clause parallel_clause collateral_clause
								if_clause bold_else_part brief_else_part
								case_clause bold_out_part brief_out_part
								conformity_clause brief_conf_out_part bold_conf_out_part
								loop_clause from_opt by_opt
								routine_text generator selection slice call cast
								dyadic_formula monadic_formula operand
%type <form>		dyadic_prefix
%type <expo>		to_opt
%type <elis>		units gunits
%type <cnfl>		conf confs
%type <inx> 		indexer trimscript bound
%type <idop>		identity_definition operation_definition routine_definition
								routine_operation_definition
%type <dex> 		nolab_series declaration
								mode_tail mode_definition priority_tail
								identity_tail operation_tail routine_tail
								routine_operation_tail 
%type <var> 		variable_tail variable_definition
					 			routine_variable_tail routine_variable_definition

%type <coll>		format_text collection_list collection
%type <pict>		pattern
								boolean_pattern integral_pattern bits_pattern string_pattern
                variable_point_pattern real_pattern complex_pattern
								integral_choice_pattern boolean_choice_pattern
								format_pattern general_pattern
%type <ins>     align str ins_opt literal
%type <expo>    replicator
%type <insr>    rep ins_rep
%type <frms>    zero_frames sign_mould digit_frames char_frames
%type <frins>   digits_finish
%type <litl>    literal_list

%%

closed_clause
	: LPAR series RPAR { $$=wrap_series($2); }
	| BEG series END	 { $$=wrap_series($2); }
	;
collateral_clause
	: LPAR unit COMMA units RPAR	{ $$=mk_coll(0,$2,$4.head); }
	| BEG unit COMMA units END		{ $$=mk_coll(0,$2,$4.head); }
	| LPAR RPAR 									{ $$.kind=coll; $$.expr.coll=0; }
	| BEG END 										{ $$.kind=coll; $$.expr.coll=0; }
	;
parallel_clause
	: PAR LPAR unit COMMA units RPAR { $$=mk_coll(1,$3,$5.head); }
	| PAR BEG unit COMMA units END	 { $$=mk_coll(1,$3,$5.head); }
	;

if_clause
	: LPAR enquiry_clause BAR series brief_else_part RPAR
			{ $$=mk_cond($2,$4,$5); }
	| IF enquiry_clause THEN series bold_else_part FI
			{ $$=mk_cond($2,$4,$5); }
	;
brief_else_part
	: 																								{ $$=mk_hip(-1,lineno); }
	| BAR series																			{ $$=wrap_series($2); }
	| AGAIN enquiry_clause BAR series brief_else_part { $$=mk_cond($2,$4,$5); }
	;
bold_else_part
	: 																								{ $$=mk_hip(-1,lineno); }
	| ELSE series 																		{ $$=wrap_series($2); }
	| ELIF enquiry_clause THEN series bold_else_part	{ $$=mk_cond($2,$4,$5); }
	;

case_clause
	: LPAR enquiry_clause BAR unit COMMA units brief_out_part RPAR
			{ $$=mk_case($2,$4,$6.head,$7); }
	| CASE enquiry_clause IN unit COMMA units bold_out_part ESAC
			{ $$=mk_case($2,$4,$6.head,$7); }
	;
brief_out_part
	: 																								{ $$=mk_hip(-1,lineno); }
	| BAR series																			{ $$=wrap_series($2); }
	| AGAIN enquiry_clause BAR unit COMMA units brief_out_part	 
			{ $$=mk_case($2,$4,$6.head,$7); }
	;
bold_out_part
	: 																								{ $$=mk_hip(-1,lineno); }
	| OUT series																			{ $$=wrap_series($2); }
	| OUSE enquiry_clause IN unit COMMA units bold_out_part
			{ $$=mk_case($2,$4,$6.head,$7); }
	;
conformity_clause
	: LPAR enquiry_clause BAR confs brief_conf_out_part RPAR
			{ $$=mk_conformity($2,$4,$5); }
	| CASE enquiry_clause IN confs bold_conf_out_part ESAC
			{ $$=mk_conformity($2,$4,$5); }
	;
confs
	: conf | confs COMMA conf { $$=conf_app($1,$3); } ;
conf
	: LPAR formol_declarer TAG RPAR COLON unit { $$=mk_conf($2,$3.id,$6); }
	| LPAR actmal_declarer TAG RPAR COLON unit { $$=mk_conf($2.mode,$3.id,$6); }
	| LPAR formol_declarer RPAR COLON unit		 { $$=mk_conf($2,-1,$5); }
	| LPAR actmal_declarer RPAR COLON unit		 { $$=mk_conf($2.mode,-1,$5); }
	;
brief_conf_out_part
	: 																								{ $$=mk_hip(-1,lineno); }
	| BAR series																			{ $$=wrap_series($2); }
	| AGAIN enquiry_clause BAR confs brief_conf_out_part
			{ $$=mk_conformity($2,$4,$5); }
	;
bold_conf_out_part
	: 																								{ $$=mk_hip(-1,lineno); }
	| OUT series																			{ $$=wrap_series($2); }
	| OUSE enquiry_clause IN confs bold_conf_out_part
			{ $$=mk_conformity($2,$4,$5); }
	;

loop_clause
	: for_opt from_opt by_opt to_opt while_opt DO series OD
			{ $$=mk_loop($1,$2,$3,$4,$5,$7); }
	;
for_opt
	: { $$=-1; } | FOR TAG { $$=$2.id; } ;
from_opt
	: { $$=mk_int("1"); } | FROM unit { $$=$2; } ;
by_opt
	: { $$=mk_int("1"); } | BY unit { $$=$2; } ;
to_opt
	: { $$=0; } | TO unit { *($$=new(expr))=$2; } ;
while_opt
	: { $$=0; } | WHILE enquiry_clause { $$=$2; } ;

series
	: unit							{ $$=mk_series(0,$1); }
	| nolab_series unit { $$=mk_series($1,$2); }
	| label_series unit { ($$=$1)->final=$2; }
	;
enquiry_clause
	: unit							{ $$=mk_series(0,$1); }
	| nolab_series unit { $$=mk_series($1,$2); }
	;
nolab_series
	: declaration SEMIC 						 { $$=$1; }
	| unit SEMIC										 { $$=add_unit(0,$1); }
	| nolab_series declaration SEMIC { $$=add_decl($1,$2); }
	| nolab_series unit SEMIC 			 { $$=add_unit($1,$2); }
	;
label_series
	: TAG COLON 											 { $$=add_label(0,$1.id); }
	| unit EXIT TAG COLON 						 { $$=mk_exit(mk_series(0,$1),$3.id); }
	| nolab_series TAG COLON					 { $$=add_label($1,$2.id); }
	| nolab_series unit EXIT TAG COLON { $$=mk_exit(mk_series($1,$2),$4.id); }
	| label_series TAG COLON					 { $$=ins_label($1,$2.id); }
	| label_series unit EXIT TAG COLON { $1->final=$2; $$=mk_exit($1,$4.id); }
	| label_series unit SEMIC 				 { ($$=$1)->prelims=add_unit($1->prelims,$2); }
	;

declaration
	: MODE mode_tail { $$=$2; } | PRIO priority_tail { $$=$2; }
	| formol_declarer identity_tail { $$=put_mode($1,$2); }
	| actmal_declarer identity_tail { $$=put_mode($1.mode,$2); frb($1.bnds); }
	| OP LPAR joined_declarer RPAR formal_declarer operation_tail
																	{ $$=put_mode(make_proc($3,$5),$6); }
	| LEAP actual_declarer variable_tail{ $$=mk_vardecs($1,$2,$3.var,$3.dex); }
	| actuol_declarer variable_tail 		{ $$=mk_vardecs(1,$1,$2.var,$2.dex); }
	| actmal_declarer variable_tail 		{ $$=mk_vardecs(1,$1,$2.var,$2.dex); }
	| PROC routine_tail 								{ $$=$2; }
	| OP routine_operation_tail 				{ $$=$2; }
	| LEAP PROC routine_variable_tail 	{ $$=mk_rvdecs($1,$3.var,$3.dex); }
	| PROC routine_variable_tail				{ $$=mk_rvdecs(LOC,$2.var,$2.dex); }
	;

/* In joined mode declarations the arguments we use |add_decl| although the
   rule is right recursive; this means that the |mode_definition| is moved
   to the far end of the list it is joined with. This is not very efficient
   if the joined declaration is very long, but has the advantage that the
   mode declaration is moved out of the way so that the other joined
   declarations can be combined collaterally. Since the resulting list will
   eventually be reversed at the outer level, the mode declarations will end
   up before the other joined declarations.
*/
mode_tail
	: mode_definition
	| mode_definition COMMA mode_tail 	{ $$=add_decl($1,$3); }
	| mode_definition COMMA declaration { $$=add_decl($1,$3); }
	;
priority_tail
	: priority_definition { $$=0; }
	| priority_definition COMMA priority_tail { $$=$3; }
	| priority_definition COMMA declaration 	{ $$=$3; }
	;
identity_tail
	: identity_definition                       { $$=add_idop($1,0); }
	| identity_definition COMMA identity_tail 	{ $$=add_idop($1,$3); }
	| identity_definition COMMA declaration 		{ $$=add_idop($1,$3); }
	;
operation_tail
	: operation_definition                      { $$=add_idop($1,0); }
	| operation_definition COMMA operation_tail { $$=add_idop($1,$3); }
	| operation_definition COMMA declaration		{ $$=add_idop($1,$3); }
	;
variable_tail
	: variable_definition
	| variable_definition COMMA variable_tail
			{ $$.var=$1.var; $$.var->next=$3.var; $$.dex=$3.dex; }
	| variable_definition COMMA declaration { $$.var=$1.var; $$.dex=$3; }
	| TAG 										{ $$.var=mk_varlist($1.id,0); $$.dex=0; }
	| TAG COMMA variable_tail { $$.var=mk_varlist($1.id,$3.var); $$.dex=$3.dex; }
	| TAG COMMA declaration 	{ $$.var=mk_varlist($1.id,0); $$.dex=$3; }
	;
routine_tail
	: routine_definition                    { $$=add_idop($1,0); }
	| routine_definition COMMA routine_tail { $$=add_idop($1,$3); }
	| routine_definition COMMA declaration	{ $$=add_idop($1,$3); }
	;
routine_operation_tail
	: routine_operation_definition                   { $$=add_idop($1,0); }
	| routine_operation_definition COMMA routine_operation_tail
		                                               { $$=add_idop($1,$3); }
	| routine_operation_definition COMMA declaration { $$=add_idop($1,$3); }
	;
routine_variable_tail
	: routine_variable_definition
	| routine_variable_definition COMMA routine_variable_tail
			{ $$.var=$1.var; $$.var->next=$3.var; $$.dex=$3.dex; }
	| routine_variable_definition COMMA declaration
			{ $$.var=$1.var; $$.dex=$3; }
	;

mode_definition
	: MODE_INDICATION EQUALS actual_declarer
			{ $$=mk_modecl($1.tag,assign_mode(get_mode($1),$3.mode),$3.bnds); }
	;
priority_definition
	: operator EQUALS DENOTATION {} ;
identity_definition
	: TAG EQUALS unit 					{ $$=mk_decl(0,$1.id,$3,0); } ;
operation_definition
	: operator EQUALS unit			{ $$=mk_decl(0,$1.op,$3,1); } ;
variable_definition /* case TAG moved: conflict with parameters */
	: TAG BECOMES unit					{ $$.var=mk_init_varlist($1.id,$3); $$.dex=0; } ;
routine_definition
	: TAG EQUALS routine_text		{ $$=mk_decl($3.expr.rout->mode,$1.id,$3,0); } ;
routine_operation_definition
	: operator EQUALS routine_text
															{ $$=mk_decl($3.expr.rout->mode,$1.op,$3,1); } ;
routine_variable_definition
	: TAG BECOMES routine_text	{ $$.var=mk_init_varlist($1.id,$3); $$.dex=0; } ;

actual_declarer
	: actmal_declarer | actuol_declarer ;
formal_declarer
	: actmal_declarer { $$=$1.mode; frb($1.bnds); } | formol_declarer ;

actmal_declarer /* could equally well by actual as formal */
	: MODE_INDICATION
			{ $$.mode=get_mode($1); $$.bnds=mk_impl($1); }
	| STANDARD
			{ $$.mode=make_prim($1.type,$1.size); $$.bnds=0; }
	| REF virtual_declarer
			{ $$.mode=make_ref($2); $$.bnds=0; }
	| STRUCT LPAR actmal_portrait RPAR
			{ $$.mode=make_struct($3.port->tags,$3.port->fields,0); free($3.port);
				$$.bnds=$3.bnds; }
	| PROC formal_declarer
			{ $$.mode=make_proc(0,$2); $$.bnds=0; }
	| PROC LPAR joined_declarer RPAR formal_declarer
			{ $$.mode=make_proc($3,$5); $$.bnds=0; }
	| UNION LPAR joined_declarer RPAR
			{ $$.mode=make_union($3); $$.bnds=0; }
	;
actmal_portrait
	: actmal_declarer actmal_portrait_tail
			{ put_fields($1.mode,($$.port=$2.port)->fields);
				$$.bnds=put_sublist($1.bnds,$2.bnds); }
	;
actmal_portrait_tail
	: TAG
			{ *($$.port=new(structnode))=new_portrait($1.id); $$.bnds=mk_rep(); }
	| TAG COMMA actmal_portrait_tail
			{ *($$.port=$3.port)=add_tag($1.id,*$3.port);
				$$.bnds=add_bounds(mk_rep(),$3.bnds); }
	| TAG COMMA actmal_portrait
			{ *($$.port=$3.port)=add_tag($1.id,*$3.port);
				$$.bnds=add_bounds(mk_rep(),$3.bnds); }
	;

actuol_declarer /* can ONLY be actual, not formal */
	: STRUCT LPAR actuol_portrait RPAR
			{ $$.mode=make_struct($3.port->tags,$3.port->fields,0); free($3.port);
				$$.bnds=$3.bnds;
			}
	| SUB actual_rower BUS actual_declarer
			{ $$.mode=make_row($2.dim,$4.mode);
				$$.bnds=add_bounds($2.bnds,$4.bnds);
			}
	| FLEX SUB actual_rower BUS actual_declarer
			{ $$.mode=make_row(-$3.dim,$5.mode);
				$$.bnds=add_bounds($3.bnds,$5.bnds);
			}
	| FLEX MODE_INDICATION
			{ $$.mode=make_row(0,get_mode($2)); $$.bnds=mk_impl($2); }
	;
actuol_portrait
	: actuol_declarer actmal_portrait_tail
			{ put_fields($1.mode,($$.port=$2.port)->fields);
				$$.bnds=put_sublist($1.bnds,$2.bnds); }
	| actuol_declarer actuol_portrait_tail
			{ put_fields($1.mode,($$.port=$2.port)->fields);
				$$.bnds=put_sublist($1.bnds,$2.bnds); }
	| actmal_declarer actuol_portrait_tail
			{ put_fields($1.mode,($$.port=$2.port)->fields);
				$$.bnds=put_sublist($1.bnds,$2.bnds); }
	;
actuol_portrait_tail
	: TAG COMMA actuol_portrait_tail
			{ *($$.port=$3.port)=add_tag($1.id,*$3.port);
				$$.bnds=add_bounds(mk_rep(),$3.bnds); }
	| TAG COMMA actuol_portrait
			{ *($$.port=$3.port)=add_tag($1.id,*$3.port);
				$$.bnds=add_bounds(mk_rep(),$3.bnds); }
	;
actual_rower
	: unit { $$.dim=1; $$.bnds=add_boundp(0,mk_int("1"),$1); }
	| unit COLON unit { $$.dim=1; $$.bnds=add_boundp(0,$1,$3); }
	| actual_rower COMMA unit
			{ $$.dim=$1.dim+1; $$.bnds=add_boundp($1.bnds,mk_int("1"),$3); }
	| actual_rower COMMA unit COLON unit
			{ $$.dim=$1.dim+1; $$.bnds=add_boundp($1.bnds,$3,$5); }
	;

formol_declarer /* can ONLY be formal, not actual */
	: STRUCT LPAR formol_portrait RPAR
			{ $$=make_struct($3.tags,$3.fields,0); }
	| SUB formal_rower BUS formal_declarer
			{ $$=make_row($2,$4); }
	;
formol_portrait
	: formol_declarer actmal_portrait_tail
			{ frb($2.bnds); $$=*$2.port; put_fields($1,$$.fields); }
	| formol_declarer formol_portrait_tail
			{ $$=$2; put_fields($1,$$.fields); }
	| actmal_declarer formol_portrait_tail
			{ $$=$2; put_fields($1.mode,$$.fields); frb($1.bnds); }
	;
formol_portrait_tail
	: TAG COMMA formol_portrait_tail { $$=add_tag($1.id,$3); }
	| TAG COMMA formol_portrait 		 { $$=add_tag($1.id,$3); }
	;
formal_rower
	: { $$=1; } | formal_rower COMMA { $$=$1+1; } ;

virtual_declarer
	: MODE_INDICATION                   { $$=get_mode($1); }
	| STANDARD                          { $$=make_prim($1.type,$1.size); }
	| REF virtual_declarer              { $$=make_ref($2); }
	| STRUCT LPAR virtual_portrait RPAR { $$=make_struct($3.tags,$3.fields,0); }
	| FLEX virtual_declarer             { $$=make_row(0,$2); }
	| SUB formal_rower BUS virtual_declarer          { $$=make_row($2,$4); }
	| PROC formal_declarer                           { $$=make_proc(0,$2); }
	| PROC LPAR joined_declarer RPAR formal_declarer { $$=make_proc($3,$5); }
	| UNION LPAR joined_declarer RPAR                { $$=make_union($3); }
	;
virtual_portrait
	: virtual_declarer virtual_portrait_tail { $$=$2; put_fields($1,$$.fields); }
	;
virtual_portrait_tail
	: TAG                                         { $$=new_portrait($1.id); }
	| TAG COMMA virtual_portrait_tail             { $$=add_tag($1.id,$3); }
	| TAG COMMA virtual_portrait                  { $$=add_tag($1.id,$3); }
	;

joined_declarer
	: joined_declarer COMMA formal_declarer       { $$=m_snoc($1,$3); }
	| formal_declarer                             { $$=m_cons($1,0); }
	;

unit
	: tertiary BECOMES unit       { $$=mk_ass($1,$3); }
	| tertiary RELATOR tertiary   { $$=mk_idrel($2,$1,$3); }
	| routine_text
	| GOTO TAG { $$=mk_hip($2.id,$2.line); }
	| SKIP { $$=mk_hip(-1,lineno); } | TILDE { $$=mk_hip(-1,lineno); }
	| dyadic_formula | monadic_formula | NIL { $$=mk_hip(-2,lineno); }
	| generator | selection
	| slice  | call | cast | DENOTATION
	| format_text { $$=mk_format($1); } | TAG { $$=mk_appl($1); }
	| closed_clause | collateral_clause | parallel_clause 
	| if_clause | case_clause | conformity_clause | loop_clause
	;
tertiary /* only REF modes allowed */
	: dyadic_formula | monadic_formula | NIL { $$=mk_hip(-2,lineno); }
	| generator | selection
	| slice  | call | cast | TAG { $$=mk_appl($1); }
	| closed_clause | if_clause | case_clause | conformity_clause
	;
secondary /* weak PREF* structured or firm (operand) */
	: generator | selection
	| slice | call | cast | DENOTATION
	| format_text { $$=mk_format($1); } | TAG { $$=mk_appl($1); }
	| closed_clause | if_clause | case_clause | conformity_clause
	;
primary /* weak PREF* ROWS or or meek procedure */
	: slice | call | cast | DENOTATION
	| TAG { $$=mk_appl($1); }
	| closed_clause | if_clause | case_clause | conformity_clause
	;
enclosed_clause
	: closed_clause { progval=$1; }
	| collateral_clause { progval=$1; } | parallel_clause { progval=$1; }
	| if_clause { progval=$1; } | case_clause { progval=$1; }
	| conformity_clause { progval=$1; } | loop_clause { progval=$1; }
	;

routine_text
	: formal_declarer COLON unit { $$=mk_routine(0,0,$1,$3); }
	| parameters formal_declarer COLON unit
			{ $$=mk_routine($1.fields,$1.tags,$2,$4); }
	;
parameters
	: LPAR formol_declarer param_tail
			{ $$=$3; put_fields($2,$$.fields); }
	| LPAR actmal_declarer param_tail
			{ $$=$3; put_fields($2.mode,$$.fields); frb($2.bnds); }
	;
param_tail
	: TAG RPAR
			{ $$=new_portrait($1.id); }
	| TAG COMMA param_tail
			{ $$=add_tag($1.id,$3); }
	| TAG COMMA formol_declarer param_tail
			{ put_fields($3,$4.fields); $$=add_tag($1.id,$4); }
	| TAG COMMA actmal_declarer param_tail
			{ put_fields($3.mode,$4.fields); frb($3.bnds); $$=add_tag($1.id,$4); }
	;
dyadic_formula
	: dyadic_prefix operand { $$=end_formula($1,$2); } ;
dyadic_prefix
	: operand operator { $$=start_formula($1,$2); }
	| dyadic_prefix operand operator { $$=extend_formula($1,$2,$3); }
	;
operand
	: monadic_formula | secondary ;
monadic_formula
	: monadic_operator operand { $$=mk_mona($1,$2); } ;
operator
	: OPERATOR | DYOP | EQUALS | TILDE ;
monadic_operator
	: OPERATOR { $$=$1.op; } | TILDE { $$=$1.op; } ;
generator
	: LEAP actual_declarer { make_ref($2.mode); $$=mk_gen($1,$2); } ;
selection
	: TAG OF secondary { $$=mk_sel($1.id,$3); } ;
slice
	: primary SUB indexer BUS { $$=mk_slice($1,$3.head); }
	; /* | primary LPAR indexer RPAR */
indexer
	: trimscript
	| indexer COMMA trimscript
			{ $$.head=$1.head; *$1.tail=$3.head; $$.tail=$3.tail; }
	;
trimscript
	: bound | AT unit 	{ $$=mk_trimmer(0,0,$2); }
	| bound COLON bound { $$=mk_trimmer(unb($1),unb($3),mk_int("1")); }
	| bound COLON bound AT unit{ $$=mk_trimmer(unb($1),unb($3),$5); }
	;
bound
	: unit { $$=mk_subscr($1); } | { $$=mk_trim(0); } ;
call
	: primary LPAR units RPAR { $$=mk_call($1,$3.head); } ;
units
	: unit { $$=expr_single($1); } | units COMMA unit { $$=expr_snoc($1,$3); } ;
cast
	: formal_declarer enclosed_clause { $$=mk_cast($1,$2); } ;

format_text
	: DOLLAR collection_list DOLLAR { $$=$2; } ;
collection_list
	: collection
	| collection COMMA collection_list { ($$=$1)->next=$3; }
	;
collection
	: ins_rep LPAR collection_list RPAR ins_opt { $$=mk_col_it($1,$3,$5); }
	| pattern { $$=finalise_pattern($1); }
	;

pattern
	: boolean_pattern | integral_pattern | real_pattern | complex_pattern 
	| string_pattern | bits_pattern | integral_choice_pattern 
	| boolean_choice_pattern | format_pattern | general_pattern
	| ins_opt { $$=mk_no_pat($1); }
	;
replicator
	: REP               { *($$=new(expr))=mk_int(name[$1]); }
	| N enclosed_clause { *($$=new(expr))=$2; }
	;
ins_opt
	: { $$=0; } | align | str	;
rep
	: ins_opt replicator { $$.ins=$1; $$.rep=$2; } ;
ins_rep
	: ins_opt { $$.ins=$1; $$.rep=0; } | rep ;
align
	: ins_rep ALIGNMENT_CODE { $$=ins_snoc($1.ins,$1.rep,$2); }	;
str
	: LITT                 { $$=ins_snoc(0,0,$1); }
	| align LITT           { $$=ins_snoc($1,0,$2); }
	| rep LITT             { $$=ins_snoc($1.ins,$1.rep,$2); }
	;

boolean_pattern
	: ins_opt B ins_opt    { $$=mk_pat(bool_patt,add_frame(0,$1,0,'b'),$3); }
	;
zero_frames
	: ins_rep Z             { $$=add_frame(0,$1.ins,$1.rep,'z'); }
	| zero_frames ins_rep Z { $$=add_frame($1,$2.ins,$2.rep,'z'); }
	;
sign_mould
	: ins_opt PLM             { $$=add_frame(0,$1,0,$2 ? '-' : '+');  }
	| zero_frames ins_opt PLM { $$=add_frame($1,$2,0,$3 ? '-' : '+'); }
	;
digit_frames
	: ins_rep DSD             { $$=add_frame(0,$1.ins,$1.rep,$2? 'D' : 'd'); }
	| ins_rep SZ              { $$=add_frame(0,$1.ins,$1.rep,'Z'); }
	| zero_frames ins_rep DSD { $$=add_frame($1,$2.ins,$2.rep,$3? 'D' : 'd'); }
	| zero_frames ins_rep SZ  { $$=add_frame($1,$2.ins,$2.rep,'Z'); }
	| digit_frames ins_rep DSD{ $$=add_frame($1,$2.ins,$2.rep,$3? 'D' : 'd'); }
	| digit_frames ins_rep SZ { $$=add_frame($1,$2.ins,$2.rep,'Z'); }
	| digit_frames ins_rep Z  { $$=add_frame($1,$2.ins,$2.rep,'z'); }
	;
digits_finish
	: zero_frames ins_opt  { $$.fr=$1; $$.ins=$2; }
	| digit_frames ins_opt { $$.fr=$1; $$.ins=$2; }
	;
integral_pattern
	: digits_finish { $$=mk_pat(int_patt,$1.fr,$1.ins); }
	| sign_mould digits_finish
	                { $$=mk_pat(int_patt,app_fr($1,$2.fr),$2.ins); }
	;

variable_point_pattern
	: integral_pattern PSPOINT ins_opt
			{ $$=mk_real_pat($1,$2,'.',0,$3); }
	| integral_pattern PSPOINT digits_finish
			{ $$=mk_real_pat($1,$2,'.',$3.fr,$3.ins); }
	| ins_opt PSPOINT digits_finish
			{ $$=mk_real_pat(mk_pat(int_patt,0,$1),$2,'.',$3.fr,$3.ins); }
	| sign_mould ins_opt PSPOINT digits_finish
			{ $$=mk_real_pat(mk_pat(int_patt,$1,$2),$3,'.',$4.fr,$4.ins); }
	;
real_pattern
	: variable_point_pattern
	| integral_pattern ESE digits_finish
			{ $$=mk_real_pat($1,$2,'e',$3.fr,$3.ins); }
	| variable_point_pattern ESE digits_finish
			{ $$=mk_real_pat($1,$2,'e',$3.fr,$3.ins); }
	| integral_pattern ESE sign_mould digits_finish
			{ $$=mk_real_pat($1,$2,'e',app_fr($3,$4.fr),$4.ins); }
	| variable_point_pattern ESE sign_mould digits_finish
			{ $$=mk_real_pat($1,$2,'e',app_fr($3,$4.fr),$4.ins); }
	;

complex_pattern
	: real_pattern ISI real_pattern { $$=mk_compl_pat($1,$2,$3); } ;

string_pattern
	: char_frames ins_opt { $$=mk_pat(string_patt,$1,$2); } ;
char_frames
	: ins_rep ASA             { $$=add_frame(0,$1.ins,$1.rep,$2? 'A' : 'a'); }
	| char_frames ins_rep ASA { $$=add_frame($1,$2.ins,$2.rep,$1? 'A' : 'a'); }
	;
bits_pattern
	: ins_opt RADIX digits_finish
		{ $$=mk_pat(radix_offset+$2,app_fr(add_frame(0,$1,0,'r'),$3.fr),$3.ins); }
	;

integral_choice_pattern
	: ins_opt C LPAR literal_list RPAR ins_opt { $$=mk_ic_pat($1,$4,$6); } ;
literal_list
	: literal                    { $$=litl_snoc(0,$1); }
	| literal_list COMMA literal { $$=litl_snoc($1,$3); }
	;
boolean_choice_pattern
	: ins_opt B LPAR literal COMMA literal RPAR ins_opt
	 		{ $$=mk_bc_pat($1,$4,$6,$8); }
	;
literal
	: LITT                    { $$=ins_snoc(0,0,$1); }
	| replicator LITT         { $$=ins_snoc(0,$1,$2); }
	| literal replicator LITT { $$=ins_snoc($1,$2,$3); }
	;

format_pattern
	: ins_opt F enclosed_clause ins_opt { $$=mk_fpat($1,$3,$4); } ;
general_pattern
	: ins_opt G ins_opt                  { $$=mk_gpat($1,0,$3); }
	| ins_opt G LPAR gunits RPAR ins_opt { $$=mk_gpat($1,$4.head,$6); }
	;
gunits
	: unit            { $$=expr_single($1); }
	|	unit COMMA unit { $$=expr_snoc(expr_single($1),$3); }
	| unit COMMA unit COMMA unit
	                  { $$=expr_snoc(expr_snoc(expr_single($1),$3),$5); }
	;
%%

static void print_std(prinode s)
{ int i,t=s.size;
	if (t!=0) for (i=abs(t); i; putchar(' '),i--) print_tok(LONG+(t<0));
	printf("%s",mode_name[s.type-INT]);
}

static void print_mi(mi_type mi) { printf("%s",bold_name[mi.tag]); }

static void print_den(denotation d)
{	if (d->mode->kind!=row && d->mode->mode.prim->type!=CHAR)
	{	int i; short l=d->mode->mode.prim->size;
		for (i=abs(l); i; i--) printf(l>0 ? "LONG " : "SHORT ");
		printf("%s",d->value);
	}
	else print_string(d->value);
}

char marker_code[]="zzadei.+-ncbfgklpqxy";

void print_token_full (int code, YYSTYPE* val)
{	char* tok=code<BECOMES ? keyword[code] : decode[code-BECOMES];
	if (code>=Z)
	{	printf("<%s marker> ",tok);
		if (code<=PSPOINT && (code==SZ || code>=ASA && val->n))	putchar('s');
		if (code>=LITT)
			if (code==LITT) print_string(name[val->monop]);
			else if (code==REP) printf("%s",name[val->monop]);
			else printf("%dr",val->n);
		else
			putchar(marker_code[
				code==ALIGNMENT_CODE ? G-Z-val->n : code-Z+(code==PLM && val->n)
				]);
	}
	else switch (code)
	{ 		 case TAG: printf("%s",name[val->tag.id]);
	break; case MODE_INDICATION: printf("%s ",tok); print_mi(val->mi);
  break; case STANDARD: printf("%s ",tok); print_std(val->std);
	break; case OPERATOR:
		if (isalpha(*bold_name[val->op.op]))
		{ printf("%s %s",tok,bold_name[val->op.op]); break; }
	/*ft*/ case DYOP: printf("%s",bold_name[val->op.op]);
	break; case DENOTATION: print_den(val->exp.expr.denot);
	break; case LEAP: printf("%s", val->n ? "LOC" : "HEAP");
	break; case RELATOR: printf("IS%s", val->n ? "" : "NT");
	break; case 0: printf("<End Of File>");
	break; default: printf("%s",tok);
	}
}

static void yyerror(char* s)
{	printf("%s in line %ld at token ",s,lineno);
	print_token_full (yychar,&yylval); printf(".\n");
}

