%term  xxif 300 xxelse 301 xxwhile 302 xxrept 303 xxdo 304 xxrb 305 xxpred 306
%term xxident 307 xxle 308 xxge 309 xxne 310 xxnum 311 xxcom 312
%term xxstring 313 xxexplist 314 xxidpar 315 xxelseif 316  xxlb 318 xxend 319
%term xxcase 320 xxswitch 321 xxuntil 322 xxdefault 323 
%term xxeq 324

%left	'|'
%left	'&'
%left	'!'
%binary	'<' '>' xxeq xxne xxge xxle
%left	'+' '-'
%left	'*' '/'
%left	xxuminus
%right	'^'

%{
#include "b.h"
#include <stdio.h>
%}

%%
%{
struct node *t;
%}


allprog:	prog xxnew
	;

prog:	stat
	|	prog stat
	;

stat:		 iftok pred nlevel elsetok nlevel
	|	 iftok  pred  nlevel
	|	xxtab whtok  pred  nlevel
	|	xxtab rpttok nlevel optuntil
	|	xxtab dotok nlevel
	|	xxtab swtok oppred pindent lbtok caseseq xxtab rbtok mindent
	|	xxtab fstok
	|	lbtok prog xxtab rbtok
	|	lbtok rbtok
	|	 labtok stat
	|	xxnl comtok stat
	|	error
	;


xxtab:		=	{
			if (!xxlablast) tab(xxindent);
			xxlablast = 0;
			}

xxnl:	=	newline();
xxnew:	=	putout('\n',"\n");
nlevel:	pindent stat mindent;
pindent:		=
				{
				if (xxstack[xxstind] != xxlb)
					++xxindent;
				};
mindent:			=
				{if (xxstack[xxstind] != xxlb && xxstack[xxstind] != xxelseif)
					--xxindent;
				pop();
				};
caseseq:	casetok caseseq
	|	casetok
	;

casetok:	xxtab xxctok predlist pindent prog mindent
	|	xxtab xxctok predlist pindent mindent
	|	xxtab deftok pindent prog mindent
	|	xxnl comtok casetok
	;

xxctok:	xxcase		=	{putout(xxcase,"case "); free ($1); push(xxcase); }


deftok:		xxdefault ':'		=		{
						putout(xxcase,"default");
						free($1);
						putout(':',":");
						free($2);
						push(xxcase);
						}
swtok:	xxswitch			=	{putout(xxswitch,"switch"); free($1); push(xxswitch); }

fstok:	xxend		=	{
				free($1);
				putout(xxident,"end");
				putout('\n',"\n");
				putout('\n',"\n");
				putout('\n',"\n");
				}
	|	xxident	=	{
				putout(xxident,$1);
				free($1);
				newflag = 1;
				forst();
				newflag = 0;
				};

		

identtok:	xxident '(' explist ')'	=	{
				xxt = addroot($1,xxident,0,0);
				$$ = addroot("",xxidpar,xxt,$3);
				}

	|	xxident		=	$$ = addroot($1,xxident,0,0);
	;

predlist:	explist  ':'		=	{
				yield($1,0);
				putout(':',":");
				freetree($1);
				}
explist:	expr ',' explist		=	$$ = addroot($2,xxexplist,checkneg($1,0),$3);
	|	expr					=	$$ = checkneg($1,0);
	;


oppred:	pred
	|
	;

pred:	'(' expr ')'	=	{ t = checkneg($2,0);
				yield(t,100);  freetree(t);	};

expr:		'(' expr ')'	=	$$ = $2;
	|	'-' expr	%prec xxuminus	=	$$ = addroot($1,xxuminus,$2,0);
	|	'+' expr	%prec xxuminus	=	$$ = $2;
	|	'!' expr	=	$$ = addroot($1,'!',$2,0);
	|	expr '+' expr	=	$$ = addroot($2,'+',$1,$3);
	|	expr '-' expr	=	$$ = addroot($2,'-',$1,$3);
	|	expr '*' expr	=	$$ = addroot($2,'*',$1,$3);
	|	expr '/' expr	=	$$ = addroot($2,'/',$1,$3);
	|	expr '^' expr	=	$$ = addroot($2,'^',$1,$3);
	|	expr '|' expr	=	$$ = addroot($2,'|',$1,$3);
	|	expr '&' expr	=	$$ = addroot($2,'&',$1,$3);
	|	expr '>' expr	=	$$ = addroot($2,'>',$1,$3);
	|	expr '<' expr	=	$$ = addroot($2,'<',$1,$3);
	|	expr xxeq expr	=	$$ = addroot($2,xxeq,$1,$3);
	|	expr xxle expr	=	$$ = addroot($2,xxle,$1,$3);
	|	expr xxge expr	=	$$ = addroot($2,xxge,$1,$3);
	|	expr xxne expr	=	$$ = addroot($2,xxne,$1,$3);
	|	identtok		=	$$ = $1;
	|	xxnum		=	$$ = addroot($1,xxnum,0,0);
	|	xxstring		=	$$ = addroot($1,xxstring,0,0);
	;

iftok:	xxif		=
				{
				if (xxstack[xxstind] == xxelse && !xxlablast)
					{
					--xxindent;
					xxstack[xxstind] = xxelseif;
					putout(' '," ");
					}
				else
					{
					if (!xxlablast)
						tab(xxindent);
					xxlablast = 0;
					}
				putout(xxif,"if");
				free($1);
				push(xxif);
				}
elsetok:	xxelse	=
				{
				tab(xxindent);
				putout(xxelse,"else");
				free($1);
				push(xxelse);
				}
whtok:	xxwhile		=	{
				putout(xxwhile,"while");
				free($1);
				push(xxwhile);
				}
rpttok:	xxrept	=			{
					putout(xxrept,"repeat");
					free($1);
					push(xxrept);
					}
optuntil:	xxtab unttok pred
		|
		;

unttok:	xxuntil	  = 	{
			putout('\t',"\t");
			putout(xxuntil,"until");
			free($1);
			}
dotok:	dopart opdotok
	;
dopart:	xxdo	identtok '=' expr  ',' expr 		=
					{push(xxdo);
					putout(xxdo,"do");
					free($1);
					puttree($2);
					putout('=',"=");
					free($3);
					puttree($4);
					putout(',',",");
					free($5);
					puttree($6);
					}
opdotok:	',' expr		=	{
						putout(',',",");
						puttree($2);
						}
	|	;
lbtok:	'{'		=	{
				putout('{'," {");
				push(xxlb);
				}
rbtok:	'}'			=	{ putout('}',"}");  pop();   }
labtok:	xxnum		=	{
				tab(xxindent);
				putout(xxnum,$1);
				putout(' ',"  ");
				xxlablast = 1;
				}
comtok:	xxcom		=	{ putout(xxcom,$1);  free($1);  xxlablast = 0; }
	|	comtok xxcom		= { putout ('\n',"\n"); putout(xxcom,$2);  free($2);  xxlablast = 0; };
%%
#define ASSERT(X,Y)	if (!(X)) error("struct bug: assertion 'X' invalid in routine Y","","");

yyerror(s)
char *s;
	{
	extern int yychar;
	fprintf(stderr,"\n%s",s);
	fprintf(stderr," in beautifying, output line %d,",xxlineno + 1);
	fprintf(stderr," on input: ");
		switch (yychar) {
			case '\t': fprintf(stderr,"\\t\n"); return;
			case '\n': fprintf(stderr,"\\n\n"); return;
			case '\0': fprintf(stderr,"$end\n"); return;
			default: fprintf(stderr,"%c\n",yychar); return;
			}
	}

yyinit(argc, argv)			/* initialize pushdown store */
int argc;
char *argv[];
	{
	xxindent = 0;
	xxbpertab = 8;
	xxmaxchars = 120;
	}


#include <signal.h>
main()
	{
	int exit();
	if ( signal(SIGINT, SIG_IGN) != SIG_IGN)
		signal(SIGINT, exit);
	yyinit();
	yyparse();
	}


putout(type,string)			/* output string with proper indentation */
int type;
char *string;
	{
	static int lasttype;
	if ( (lasttype != 0) && (lasttype != '\n') && (lasttype != ' ') && (lasttype != '\t') && (type == xxcom))
		accum("\t");
	else if (lasttype == xxcom && type != '\n')
		tab(xxindent);
	else
		if (lasttype == xxif	||
			lasttype == xxwhile	||
			lasttype == xxdo	||
			type == '='	||
			lasttype == '='	||
			(lasttype == xxident && (type == xxident || type == xxnum) )	||
			(lasttype == xxnum && type == xxnum) )
			accum(" ");
	accum(string);
	lasttype = type;
	}


accum(token)		/* fill output buffer, generate continuation lines */
char *token;
	{
	static char *buffer;
	static int lstatus,llen,bufind;
	int tstatus,tlen,i;

#define NEW	0
#define MID	1
#define CONT	2

	if (buffer == 0)
		{
		buffer = malloc(xxmaxchars);
		if (buffer == 0) error("malloc out of space","","");
		}
	tlen = slength(token);
	if (tlen == 0) return;
	for (i = 0; i < tlen; ++i)
		ASSERT(token[i] != '\n' || tlen == 1,accum);
	switch(token[tlen-1])
		{
		case '\n':	tstatus = NEW;
				break;
		case '+':
		case '-':
		case '*':
		case ',':
		case '|':
		case '&':
		case '(':	tstatus = CONT;
				break;
		default:	tstatus = MID;
		}
	if (llen + bufind + tlen > xxmaxchars && lstatus == CONT && tstatus != NEW)
		{
		putchar('\n');
		++xxlineno;
		for (i = 0; i < xxindent; ++i)
			putchar('\t');
		putchar(' ');putchar(' ');
		llen = 2 + xxindent * xxbpertab;
		lstatus = NEW;
		}
	if (lstatus == CONT && tstatus == MID)
		{			/* store in buffer in case need \n after last CONT char */
		ASSERT(bufind + tlen < xxmaxchars,accum);
		for (i = 0; i < tlen; ++i)
			buffer[bufind++] = token[i];
		}
	else
		{
		for (i = 0; i < bufind; ++i)
			putchar(buffer[i]);
		llen += bufind;
		bufind = 0;
		for (i = 0; i < tlen; ++i)
			putchar(token[i]);
		if (tstatus == NEW) ++xxlineno;
		llen = (tstatus == NEW) ? 0 : llen + tlen;
		lstatus = tstatus;
		}
	}

tab(n)
int n;
	{
	int i;
	newline();
	for ( i = 0;  i < n; ++i)
		putout('\t',"\t");
	}

newline()
	{
	static int already;
	if (already)
		putout('\n',"\n");
	else
		already = 1;
	}

error(mess1, mess2, mess3)
char *mess1, *mess2, *mess3;
	{
	fprintf(stderr,"\nerror in beautifying, output line %d: %s %s %s \n",
		xxlineno, mess1, mess2, mess3);
	exit(1);
	}







push(type)
int type;
	{
	if (++xxstind > xxtop)
		error("nesting too deep, stack overflow","","");
	xxstack[xxstind] = type;
	}

pop()
	{
	if (xxstind <= 0)
		error("stack exhausted, can't be popped as requested","","");
	--xxstind;
	}


forst()
	{
	while( (xxval = yylex()) != '\n')
		{
		putout(xxval, yylval);
		free(yylval);
		}
	free(yylval);
	}
