%%
%% This is file `infix-RPN.tex',
%%
%% IMPORTANT NOTICE:
%%
%% Package `infix-RPN.tex'
%%
%% Main code:
%%   Jean-C�me Charpentier <[email protected]>
%%
%% Contributions by
%%   Christophe Jorssen <[email protected]>
%%   `libre' is the french word for `free' :-)
%%
%% This program can be redistributed and/or modified under the terms
%% of the LaTeX Project Public License Distributed from CTAN archives
%% in directory CTAN:/macros/latex/base/lppl.txt.
%%
%% DESCRIPTION:
%%   `infix-RPN' is a package to convert infix expressions to
%%    Reverse Polish Notation
%%
%%
\def\RCS$#1: #2 ${\expandafter\def\csname RCS#1\endcsname{#2}}
\RCS$Revision: 1.7 $
\RCS$Date: 2004-07-06 23:41:52+02 $

\def\fileversion{0.11}
\csname infixRPNLoaded\endcsname
\let\infixRPNLoaded\endinput
\message{`infix-RPN' v\fileversion\space (Rev \RCSRevision, \RCSDate), J.-C.Charpentier/C.Jorssen}

\edef\opAtCode{\the\catcode`\@}
\edef\opHatCode{\the\catcode`\^}
\edef\opUnderscoreCode{\the\catcode`\_}
\catcode`\@=11\relax
\catcode`\^=12\relax
\catcode`\_=11\relax

\def\s@pow{exp}
\def\s@lpar{(}
\def\s@rpar{)}
\def\s@comma{,}

\def\DeclareNewPSOperator{%
 \bgroup
   \catcode`\_=11\relax
   \DeclareNewPSOperator@i
}

\def\DeclareNewPSOperator@i#1{%
   \expandafter\ifx\csname PS@operator@list\endcsname\relax
     \gdef\PS@operator@list{#1}%
   \else
     \xdef\PS@operator@list{#1,\PS@operator@list}%
   \fi
   \expandafter\gdef\csname s@#1\endcsname{#1}%
 \egroup
}

\DeclareNewPSOperator{add}
\DeclareNewPSOperator{sub}
\DeclareNewPSOperator{mul}
\DeclareNewPSOperator{div}
\DeclareNewPSOperator{exp}
\DeclareNewPSOperator{abs}
\DeclareNewPSOperator{sin}
\DeclareNewPSOperator{cos}
\DeclareNewPSOperator{atan}
\DeclareNewPSOperator{neg}
\DeclareNewPSOperator{ceiling}
\DeclareNewPSOperator{floor}
\DeclareNewPSOperator{truncate}
\DeclareNewPSOperator{sqrt}
\DeclareNewPSOperator{ln}
\DeclareNewPSOperator{log}


\newcount\@parenthesis
\newcount\token@cpt
\newif\if@begin@token
\newif\if@in@number
\newif\if@in@decimal
\newif\if@in@name
\newif\if@sign
\def\@tokencreate#1{%
 \expandafter\xdef\csname op@token\the\token@cpt\endcsname{#1}%
 \global\advance\token@cpt\@ne
 \expandafter\global
 \expandafter\let\csname op@token\the\token@cpt\endcsname\relax
 \global\advance\token@cpt\m@ne
}
\def\@tokenappend#1{%
 \expandafter\xdef\csname op@token\the\token@cpt\endcsname
   {\csname op@token\the\token@cpt\endcsname#1}%
}
\def\@tokensingle#1{%
 \edef\@arg{#1}%
 \if@in@name
   \global\advance\token@cpt\@ne
   \@in@namefalse
 \fi
 \if@in@number
   \global\advance\token@cpt\@ne
   \@in@numberfalse
   \@in@decimalfalse
 \fi
 \ifx\@arg\s@add
   \if@sign
     % ignore + sign
     \global\advance\token@cpt\m@ne
   \else
     \@tokencreate{#1}%
   \fi
 \else\ifx\@arg\s@sub
   \if@sign
     \@tokencreate{\s@neg}%
   \else
     \@tokencreate{#1}%
   \fi
 \else
   \@tokencreate{#1}%
 \fi\fi
 \global\advance\token@cpt\@ne
}
\def\@tokenuse#1{%
 \expandafter\ifx\csname op@token#1\endcsname\s@comma%
 \else
   \xdef\RPN{\RPN\space\csname op@token#1\endcsname}%
 \fi
}

\let\endscanline\relax
\def\scan@line{%
 \begingroup
 \catcode`\ =12
 \@parenthesis=\z@
 \@in@numberfalse
 \@in@decimalfalse
 \@in@namefalse
 \global\token@cpt=\@ne
 \global\@signtrue
 \scan@@line
}
\def\scan@@line#1{\scan@@@line#1\endscanline\endgroup}
\def\scan@@@line#1#2\endscanline{%
 \op@testchar{#1}%
 \ifop@isdigit
   \global\@signfalse
   \if@in@number
     \@tokenappend{#1}%
   \else \if@in@name
     \@in@namefalse
     \@in@numbertrue
     \@tokenappend{#1}%
   \else
     \@in@numbertrue
     \@tokencreate{#1}%
   \fi\fi
 \fi
 \ifop@isplus
   \@tokensingle{\s@add}%
   \global\@signtrue
 \fi
 \ifop@isminus
   \@tokensingle{\s@sub}%
   \global\@signtrue
 \fi
 \ifop@ismultiply
   \@tokensingle{\s@mul}%
   \global\@signtrue
 \fi
 \ifop@isdivide
   \@tokensingle{\s@div}%
   \global\@signtrue
 \fi
 \ifop@ispower
   \@tokensingle{\s@pow}%
   \global\@signtrue
 \fi
 \ifop@isdecimalsep
   \global\@signfalse
   \if@in@decimal
     \errmessage{Syntax error: number with multiple separators!}%
   \else \if@in@number
     \@in@decimaltrue
     \@tokenappend{.}%
   \else
     \@tokencreate{.}%
     \@in@numbertrue
     \@in@decimaltrue
   \fi\fi
 \fi
 \ifop@iscomma
   \@tokensingle{,}%
   \global\@signtrue
 \fi
 \ifop@islparenthesis
   \@tokensingle{(}%
   \global\@signtrue
 \fi
 \ifop@isrparenthesis
   \global\@signfalse
   \@tokensingle{)}%
 \fi
 \ifop@isspace
   \if@in@number
     \@in@numberfalse
     \@in@decimalfalse
     \global\advance\token@cpt\@ne
   \else \if@in@name
     \@in@namefalse
     \global\advance\token@cpt\@ne
   \fi\fi
 \fi
 \ifop@isother
   \global\@signfalse
   \if@in@name
     \@tokenappend{#1}%
   \else \if@in@number
     \@in@numberfalse
     \@in@decimalfalse
     \@in@nametrue
     \@tokenappend{#1}%
   \else
     \@in@nametrue
     \@tokencreate{#1}%
   \fi\fi
 \fi
 \def\arg{#2}%
 \ifx\empty\arg
   \let\next\relax
 \else
   \let\next\scan@@@line
 \fi
 \expandafter\next\arg\endscanline
}
\count255=`\0 \edef\op@numbegin{\the\count255}
\count255=`\9 \edef\op@numend{\the\count255}
\count255=`\+ \edef\op@plus{\the\count255}
\count255=`\- \edef\op@minus{\the\count255}
\count255=`\* \edef\op@multiply{\the\count255}
\count255=`\/ \edef\op@divide{\the\count255}
\count255=`\^ \edef\op@power{\the\count255}
\count255=`\. \edef\op@dot{\the\count255}
\count255=`\, \edef\op@comma{\the\count255}
\count255=`\( \edef\op@lparenthesis{\the\count255}
\count255=`\) \edef\op@rparenthesis{\the\count255}
\edef\op@space{32}
\newif\ifop@isdigit
\newif\ifop@isplus
\newif\ifop@isminus
\newif\ifop@ismultiply
\newif\ifop@isdivide
\newif\ifop@ispower
\newif\ifop@isdecimalsep
\newif\ifop@iscomma
\newif\ifop@islparenthesis
\newif\ifop@isrparenthesis
\newif\ifop@isspace
\newif\ifop@isother
\def\op@testchar#1{%
 \op@isdigitfalse
 \op@isplusfalse
 \op@isminusfalse
 \op@ismultiplyfalse
 \op@isdividefalse
 \op@ispowerfalse
 \op@isdecimalsepfalse
 \op@iscommafalse
 \op@islparenthesisfalse
 \op@isrparenthesisfalse
 \op@isspacefalse
 \op@isotherfalse
 \count255=`#1\relax
 \ifnum\count255=\op@plus \relax
   \op@isplustrue
 \else \ifnum\count255=\op@minus \relax
   \op@isminustrue
 \else \ifnum\count255=\op@multiply \relax
   \op@ismultiplytrue
 \else \ifnum\count255=\op@divide \relax
   \op@isdividetrue
 \else \ifnum\count255=\op@power \relax
   \op@ispowertrue
 \else \ifnum\count255=\op@dot \relax
   \op@isdecimalseptrue
 \else \ifnum\count255=\op@comma \relax
   \op@iscommatrue
 \else \ifnum\count255=\op@lparenthesis \relax
   \op@islparenthesistrue
 \else \ifnum\count255=\op@rparenthesis \relax
   \op@isrparenthesistrue
 \else \ifnum\count255=\op@space \relax
   \op@isspacetrue
 \else \ifnum\count255<\op@numbegin \relax
   \op@isothertrue
 \else \ifnum\count255>\op@numend \relax
   \op@isothertrue
 \else \op@isdigittrue
 \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
}

\def\search@term#1#2{%
 \begingroup
 \count1=#1\relax
 \count255=#2\relax
 \ifnum\count1=\count255
   \@tokenuse{#1}%
 \else
   \count5=\count255
   \count7=\count1
   \advance\count7\m@ne
   \count3=\z@
   \loop
   \ifnum\count5>\count7
     \expandafter\ifx\csname op@token\the\count5\endcsname\s@rpar\relax
       \advance\@parenthesis\@ne
     \fi
     \expandafter\ifx\csname op@token\the\count5\endcsname\s@lpar\relax
       \advance\@parenthesis\m@ne
     \fi
     \expandafter\ifx\csname op@token\the\count5\endcsname\s@add\relax
       \ifnum\@parenthesis=\z@
         \count3=\count5
         \count5=\z@
       \fi
     \fi
     \expandafter\ifx\csname op@token\the\count5\endcsname\s@sub\relax
       \ifnum\@parenthesis=\z@
         \count3=\count5
         \count5=\z@
       \fi
     \fi
     \expandafter\ifx\csname op@token\the\count5\endcsname\s@comma\relax
       \ifnum\@parenthesis=\z@
         \count3=\count5
         \count5=\z@
       \fi
     \fi
     \advance\count5\m@ne
   \repeat
   \ifnum\count3=\z@
     \ifnum\@parenthesis=\z@
       \search@factor{\the\count1}{\the\count255}%
     \else
       \errmessage{Syntax error: unbalanced parenthesis!}%
     \fi
   \else
     \advance\count3\m@ne
     \search@term{\the\count1}{\the\count3}%
     \advance\count3\tw@
     \search@term{\the\count3}{\the\count255}%
     \advance\count3\m@ne
     \@tokenuse{\the\count3}%
   \fi
 \fi
 \endgroup
}
\def\search@factor#1#2{%
 \begingroup
 \count1=#1\relax
 \count255=#2\relax
 \ifnum\count1=\count255
   \@tokenuse{\the\count1}%
 \else
   \count5=\count255
   \count7=\count1
   \advance\count7\m@ne
   \count3=\z@
   \loop
   \ifnum\count5>\count7
     \expandafter\ifx\csname op@token\the\count5\endcsname\s@rpar\relax
       \advance\@parenthesis\@ne
     \fi
     \expandafter\ifx\csname op@token\the\count5\endcsname\s@lpar\relax
       \advance\@parenthesis\m@ne
     \fi
     \expandafter\ifx\csname op@token\the\count5\endcsname\s@mul\relax
       \ifnum\@parenthesis=\z@
         \count3=\count5
         \count5=\z@
       \fi
     \fi
     \expandafter\ifx\csname op@token\the\count5\endcsname\s@div\relax
       \ifnum\@parenthesis=\z@
         \count3=\count5
         \count5=\z@
       \fi
     \fi
     \advance\count5\m@ne
   \repeat
   \ifnum\count3=\z@
     \ifnum\@parenthesis=\z@
       \search@power{\the\count1}{\the\count255}%
     \else
       \errmessage{! Syntax error: unbalanced parenthesis}%
     \fi
   \else
     \advance\count3\m@ne
     \search@factor{\the\count1}{\the\count3}%
     \advance\count3\tw@
     \search@factor{\the\count3}{\the\count255}%
     \advance\count3\m@ne
     \@tokenuse{\the\count3}%
   \fi
 \fi
 \endgroup
}
\def\search@power#1#2{%
 \begingroup
 \count1=#1\relax
 \count255=#2\relax
 \ifnum\count1=\count255
   \@tokenuse{#1}%
 \else
   \count5=\count255
   \count7=\count1
   \advance\count7\m@ne
   \count3=\z@
   \loop
   \ifnum\count5>\count7
     \expandafter\ifx\csname op@token\the\count5\endcsname\s@rpar\relax
       \advance\@parenthesis\@ne
     \fi
     \expandafter\ifx\csname op@token\the\count5\endcsname\s@lpar\relax
       \advance\@parenthesis\m@ne
     \fi
     \expandafter\ifx\csname op@token\the\count5\endcsname\s@pow\relax
       \ifnum\@parenthesis=\z@
         \count3=\count5
         \count5=\z@
       \fi
     \fi
     \advance\count5\m@ne
   \repeat
   \ifnum\count3=\z@
     \ifnum\@parenthesis=\z@
       \search@primary{\the\count1}{\the\count255}%
     \else
       \errmessage{Syntax error: unbalanced parenthesis}%
     \fi
   \else
     \advance\count3\m@ne
     \search@power{\the\count1}{\the\count3}%
     \advance\count3\tw@
     \search@power{\the\count3}{\the\count255}%
     \advance\count3\m@ne
     \@tokenuse{\the\count3}%
   \fi
 \fi
 \endgroup
}
\def\search@primary#1#2{%
 \begingroup
 \count1=#1\relax
 \count255=#2\relax
 \ifnum\count1=\count255
   \@tokenuse{#1}%
 \else
   \edef\current@cnt{#1}%
   \expandafter\compare@PS@operator\PS@operator@list,\@nil
   \expandafter\ifx\csname op@token#1\endcsname\s@lpar\relax
     \expandafter\ifx\csname op@token#2\endcsname\s@rpar\relax
       \advance\count1\@ne
       \advance\count255\m@ne
       \search@term{\the\count1}{\the\count255}%
     \else
       \errmessage{Syntax error: Garbage after parenthesis
       (tokens '#1' to '#2')}%
     \fi
   \fi
 \fi
 \endgroup
}

\let\@nil\relax

\def\compare@PS@operator#1,#2\@nil{%
 \def\@tempa{#1}%
 \def\@tempb{#2}%
 \expandafter\ifx\csname op@token\current@cnt\endcsname\@tempa%
   \advance\count1\@ne
   \search@primary{\the\count1}{\the\count255}%
   \advance\count1\m@ne
   \@tokenuse{\the\count1}%
 \fi
 \ifx\@tempb\empty
   \let\next\relax
   \let\@tempb\relax
 \else
   \let\next\compare@PS@operator
 \fi
 \expandafter\next\@tempb\@nil
}


\def\infixtoRPN{%
 \begingroup
 \catcode`\ =12
 \catcode`\^=12
 \infixt@RPN
}
\def\infixt@RPN#1{%
 \xdef\@expression{#1}%
 \endgroup
 \def\RPN{}%
 \expandafter\scan@line\expandafter{\@expression}%
 \expandafter\ifx\csname op@token\the\token@cpt\endcsname\relax
   \advance\token@cpt\m@ne
 \fi
 \search@term{1}{\the\token@cpt}%
}

\catcode`\@=\opAtCode\relax
\catcode`\^=\opHatCode\relax
\catcode`\_=\opUnderscoreCode\relax
\endinput