%begin; ! Z80 assembler source profiler

%constinteger maxtag=511,maxcell=5000

%recordformat tf(%integer t1,t2,first)
%recordformat lf(%integer line,next)
%record(tf)%array tag(0:maxtag)
%record(lf)%array list(1:maxcell)
%integerarray sortp(0:maxtag)

%record(tf)%name t
%record(lf)%name l

%integer line=1
%integer free=1
%integer max=maxtag
%integer sym,t1,t2,i,p,pos,temp

%routine skipnumber
%integer max,num,base
   base=10; num=sym-'0'
   %cycle
      max=base-1+'0'; max=max+7 %if base>10
      %cycle
         sym=nextsymbol
         %exitif sym='_'
         %returnif sym<'0'
         sym=sym-32 %if 'a'<=sym<='z'
         %returnif sym>max
         sym=sym-'0'; sym=sym-7 %if sym>9
         num=num*base+sym
         readsymbol(sym)
      %repeat
      readsymbol(sym)
      base=num; num=0
   %repeat
%end

%integerfn gettag
%integer t,i
   t=0
   %for i=2,-1,0 %cycle
      %if '0'<=sym<='9' %start
         sym=sym-'0'+1
      %elseif 'A'<=sym<='Z' %start
         sym=sym-'A'+11
      %elsestart
         %result=t
      %finish
      t=38\\i*sym+t
      readsymbol(sym)
      sym=sym-32 %if 'a'<=sym<='z'
   %repeat
   %result=t
%end

%routine puttag(%integer t)
%ownintegerarray x(0:36)=' ','0','1','2','3','4','5','6','7','8','9',
'A','B','C','D','E','F','G','H','I','J','K','L','M',
'N','O','P','Q','R','S','T','U','V','W','X','Y','Z'
%integer a,b,c
   b=(t>>1)//19; c=t-b*38
   a=b//38; b=b-a*38
   printsymbol(x(a)); printsymbol(x(b)); printsymbol(x(c))
%end

%routine print
   %for i=0,1,max %cycle
      t==tag(sortp(i)); p=t_first
      %if p#0 %start
         pos=0
         %cycle
            l==list(p); temp=l_next; l_next=pos
            %exitif temp=0; l_next=pos; pos=p; p=temp
         %repeat
         puttag(t_t1); puttag(t_t2); space; pos=7
         %cycle
            line=l_line; p=l_next
            spaces(7) %and pos=7 %if pos=0
            write(line<<2>>2,4); pos=pos+6
            %if line<0 %start
               %if line<<1<0 %then printsymbol('#') %else printsymbol('*')
            %finish
            %if pos>=74 %start
               pos=0; newline
            %finish
            space %if line>=0 %and pos#0
            p=l_next; %exitif p=0
            l==list(p)
         %repeat
         newline %unless pos=0
      %finish
   %repeat
%end

%routine sort
   %integerfn dif(%integer i,j)
   %integer k
      k=(i>>1)-(j>>1); k=(i&1)-(j&1) %if k=0
      %result=k
   %end
   %integerfn compare(%integer i,j)
   %record(tf)%name ii,jj
      ii==tag(sortp(i)); jj==tag(sortp(j))
      i=dif(ii_t1,jj_t1); %result=i %unless i=0
      %result=dif(ii_t2,jj_t2)
   %end
   %routine swop(%integer i,j)
   %integer k
      k=sortp(i); sortp(i)=sortp(j); sortp(j)=k
   %end
%integer i,j
   max=-1
   %for i=0,1,maxtag %cycle
      %if tag(i)_first#0 %start
         max=max+1; sortp(max)=i
      %finish
   %repeat
   write(max+1,1)
   %for i=max,-1,1 %cycle
      %for j=1,1,i %cycle
         swop(j-1,j) %if compare(j-1,j)>0
      %repeat
      newline %if i&63=0; printsymbol('.')
   %repeat
   newline
%end

%onevent 9 %start
   selectoutput(2); sort
   selectoutput(1); print
   %stop
%finish

%for i=0,1,maxtag %cycle
   tag(i)_first=0
%repeat

selectoutput(0)
selectinput(1)
%cycle
   readsymbol(sym) %until sym#' '
   sym=sym-32 %if 'a'<=sym<='z'
   %if 'A'<=sym<='Z' %start
      t1=gettag; t2=gettag
      %unless t2=0 %start
         %cycle; %repeatuntil gettag=0
      %finish
      i=maxtag; p=(t1!!t2)&maxtag
      %cycle
         t==tag(p); p=(p+1)&maxtag
         %if t_first=0 %start
            t_t1=t1; t_t2=t2; t_first=free
            l==list(free); free=free+1
            l_next=0; l_line=line
            %exit
         %finish
         %if t_t1=t1 %and t_t2=t2 %start
            l==list(t_first)
            %exitif l_line<<1>>1=line
            l==list(free); free=free+1
            l_next=t_first; t_first=free-1
            l_line=line
            %exit
         %finish
         i=i-1
         %if i<0 %start
            printstring("Too many tags
");         %signal 9
         %finish
      %repeat
   %finish
   %if '0'<=sym<='9' %start
      skipnumber
   %elseif sym=',' %start
      l_line=l_line!16_8000
   %elseif sym=':' %or sym='=' %start
      l_line=l_line!16_c000
   %elseif sym=nl %start
      line=line+1
   %elseif sym='/' %start
      line=line+1
      readsymbol(sym) %until sym=nl
   %finish
%repeat

%endofprogram
