#!/usr/bin/env perl

sub beginCode
{ if ( $code == 0 )
  { print "\\begin{pcecode}\n";
    $code = 1;
  }
}


sub endCode
{ if ( $code == 1 )
  { print "\\end{pcecode}\n\n\\noindent\n";
    $code = 0;
  }
}


sub skipblanklines
{ if ( /^\s*$/ )
  { $blanklines = 1;
    while (<ARGV>)
    { if ( /^\s*$/ )
      { $blanklines++;
      } else
      { last;
      }
    }
    return $blanklines;
  } else
  { return 0;
  }
}


sub quoteline
{ if ( $list eq "shortlist" && /^\s*#\s*(.*)$/ )
  { print "\\item {\\it ";
    $_ = $1;
    &printTeX;
    print "}\\mbox{}\\\\\n";
  } elsif ( $list eq "shortlist" && /^\s*[-*]\s*(.*)$/ )
  { print "\\item\n\n";
    $_ = $1;
    &printTeX;
  } elsif ( $list eq "enum" && /^\s*\d+\)\s*(.*)$/ )
  { print "\\item\n\n";
    $_ = $1;
    &printTeX;
  } elsif ( $list eq "code" )
  { &expandTabs;
    print;
  } else
  { &printTeX;
  }
}


sub quote
{ if ( /^\s*[-*#]/ )
  { $list = "shortlist";
  } elsif ( /^\s*\d+\)/ )
  { $list = "enum";
  } else
  { $list = "code";
  }
  print "\\begin{$list}\n";
  &quoteline;
  while (<ARGV>)
  { $blanklines = &skipblanklines;

    if ( /^\S/ )
    { print "\\end{$list}\n";
      if ( $list eq "code" )
      { print "\\noindent\n";
      }
      return;
    }
    &quoteline;
  }
}


sub footnote
{ /^NOTE:\t(.*)$/;
  print "\\footnote{";
  $_ = $1;
  &printTeX;

  while (<ARGV>)
  { if ( /^\S/ )
    { print "}\n";
      return;
    }
    chop;
    print "\n";
    &printTeX;
  }
}


sub comment
{ &endCode;

  while (<ARGV>)
  { $blanklines = &skipblanklines;

    while ( /^NOTE:\t/ )
    { &footnote;
      next;
    }

    if (/^(- )+\*\//)
    { print "\n";
      return;
    }

    if ( $blanklines > 0 && /^\t/ )
    { &quote;
      if (/^(- )+\*\//)
      { print "\n";
	return;
      }
      &printTeX;
    } else
    { for($i=0; $i<$blanklines; $i++)
      { print "\n";
      }
      &printTeX;
    }
  }
}


sub printTeX
{ s/`([@\w]+)\s*<->(\w+)/\\index{\l\1,\\both{\2}}`\1 \\both{\2}/g;
  s/`([@\w]+)\s*<-(\w+)/\\index{\l\1,\\get{\2}}`\1 \\get{\2}/g;
  s/`([@\w]+)\s*->(\w+)/\\index{\l\1,\\send{\2}}`\1 \\send{\2}/g;
  s/<->(\w+)/\\both{\1}/g;
  s/<-(\w+)/\\get{\1}/g;
  s/->(\w+)/\\send{\1}/g;
  s/(\w+)\/((\d+|\[\d+-\d+\]))/\\index{\1\/\2}\\predref{\1}{\2}/g;
  s/(\w+\.pl)/\\index{\1}\1/g;
  s/(\w\.\w)\.(\s+[a-z])/\1.\\\2/g;
  s/(^|[^\w}])@(\w+)/\1\\index{@\2}\\objectname{\2}/g;
  s/<(\w[-\w]+)>/\\bnfmeta{\1}/g;

  print;
}


sub header
{ while (<ARGV>)
  { &printCode;
    if (/^\*\//)
    { return;
    }
  }
}


sub lower
{ local($word) = @_;

  $word =~ tr/A-Z/a-z/;
  return $word;
}


sub subheader
{ &endCode;
  while (<ARGV>)
  { if ( /^\s+\*\s+((\s*\S+)+)\s+\*\s$/ )
    { $header = &lower($1);
      print "\n\\$subsectionkind{$header}\n\n";
    } elsif (/\*\//)
    { return;
    }
  }
}


sub expandTabs
{ while ( ($i = index($_, "\t")) != $[-1 )
  { $nspaces = 8 - $i % 8;
    for( $spaces="", $i=0; $i<$nspaces; $i++ )
    { $spaces .= " ";
    }
    s/\t/$spaces/;
  }
}


sub countArity
{ local ($args) = @_;

  $arity = 1;
  $bracketnesting = 0;

  for($i=0; $i<length($args); $i++)
  { $c = substr($args, $i, 1);

    if ( $c eq "," && $bracketnesting == 0 )
    { $arity++;
    } elsif ( $c =~ /[[({]/ )
    { $bracketnesting++;
    } elsif ( $c =~ /[])}]/ )
    { $bracketnesting--;
    }
  }

  return $arity;
}

sub printCode
{ if ( /^\s*$/ )
  { $blanks++;
  } else
  { if ( $code == 1 )
    { for($i=0; $i<$blanks; $i++)
      { print "\\vskip 5pt\n";
      }
    } else
    { &beginCode;
    }
    $blanks = 0;

    if ( /^\s*:-\s*pce_begin_class\(\s*(\w+)\s*,/ )
    { $class = $1;
      print "\\index{$class}";
    } elsif ( /^(\w+)\(.*\)\s*:->/ )
    { print "\\index{$class,\\send{$1}}";
    } elsif ( /^(\w+)\(.*\)\s*:<-/ )
    { print "\\index{$class,\\get{$1}}";
    } elsif ( /^variable\(\s*(\w+),[^,]*,\s*get/ )
    { print "\\index{$class,\\get{$1}}";
    } elsif ( /^variable\(\s*(\w+),[^,]*,\s*send/ )
    { print "\\index{$class,\\send{$1}}";
    } elsif ( /^variable\(\s*(\w+),[^,]*,\s*both/ )
    { print "\\index{$class,\\both{$1}}";
    } elsif ( /^(\w+)\((.*\))\s*:-\s*(%|$)/ )
    { $arity = &countArity($2);
      print "\\index{$1\/$arity}";
    } elsif ( /^(\w+)\s*:-/ )
    { print "\\index{$1\/0}";
    } elsif ( /@(\w+)/ )
    { print "\\index{\@$1}";
    }

    $lineno++;
    print "\\lineno{$lineno}";
    if ( /\t*"(.*)"::\s*$/ )
    { print "\\verb\$        \"\${\\normalsize\\rm{}";
      $_ = $1;
      &printTeX;
      print "}\\verb\$\"::\$\n";
    } else
    { chop;
      &expandTabs;
      if ( ! /\$/ )
      { print "\\verb\$$_\$\n";
      } else
      { if ( ! /\|/ )
        { print "\\verb|$_|\n";
        } else
	{ if ( ! /#/ )
	  { print "\\verb#$_#\n";
	  } else
	  { print "\\verb&$_&\n";
	  }
	}
      }
    }
  }
}


#	MAIN PROGRAM

$printHeader = 1;
$subsectionkind = "subsection";

while (<>)
{ if (/^\/\*\s+\$Id: ([^,]+)/)
  { if ( $printHeader )
    { print "\\section{Source file ``$1''}\n\n";
      &beginCode;
      &printCode;

      &header;
    } else
    { while (<ARGV>)
      { last if /^\*\//;
      }
    }
    next;
  }

  if (/\/(\*){20}/)
  { &subheader;
    next;
  }

  if (/^\/\*( -)+/)
  { &comment;
    next;
  }

  &printCode;
}

&endCode;
