% \iffalse meta-comment % vim: tw=80 % %% File: algobox.dtx (C) Copyright 2016-2019 RIVAUD Julien %% %% It may be distributed and/or modified under the conditions of the %% General Public License (GPL), either version 3 of this %% license or (at your option) any later version. % %<*driver|package> % The version of expl3 required is tested as early as possible, as % some really old versions do not define \ProvidesExplPackage. \NeedsTeXFormat{LaTeX2e}[1995/12/01] \RequirePackage{expl3}[2018/06/19] \def\ExplFileName{algobox} \def\ExplFileDescription{Typeset Algobox programs} \def\ExplFileDate{2019/09/29} \def\ExplFileVersion{1.3} % %<*driver> \documentclass[full,a4paper]{l3doc} \usepackage{fontspec} \usepackage{algobox} \usepackage{url} \begin{document} \def\Algobox{\textsc{AlgoBox}} \DocInput{\jobname.dtx} \end{document} % % \fi % % \title{^^A % The \textsf{\ExplFileName} package\\ \ExplFileDescription^^A % \thanks{This file describes v\ExplFileVersion, % last revised \ExplFileDate.}^^A % } % % \author{^^A % Julien ``\_FrnchFrgg\_'' \textsc{Rivaud}\thanks % {^^A % E-mail: % \href{mailto:frnchfrgg@free.fr} % {frnchfrgg@free.fr}^^A % }^^A % } % % \date{Released \ExplFileDate} % % \maketitle % % \begin{documentation} % % \section{Documentation} % % \subsection{Getting support} % % If you find bugs or keywords not recognized by the package, you can report it % at the address \url{https://gitlab.com/frnchfrgg-latex/algobox/issues}. % % \subsection{Rationale} % % French mathematics and/or computer science teachers can use \Algobox\ % (\url{http://www.xm1math.net/algobox/}) to teach algorithmics to beginners. % It uses tree-like indentation, fixed-form structures entered by buttons and % dialogs rather than free text. This prevents most typos or small beginner % mistakes that are often hard to detect. % % \Algobox\ can save a project in its own format, and export in a variety of % formats, including \LaTeX. Several problems arise: % \begin{itemize} % \item The output is not similar to what \Algobox\ displays itself. % \item The generated code is standalone and uses dependencies that might not % be wanted, like \textsf{algorithm} and \textsf{algpseudocode} that can % clash with other algorithm-like packages. % \item The algorithm part of the generated code does not look like \Algobox\ % code and can thus be annoying to modify by hand if needed. % \end{itemize} % % This small package intends to solve the problem by using a syntax very close % to the real \Algobox\ syntax and having a typeset output of the best quality % possible, resembling the most to what \Algobox\ displays in its editing % window. % % \subsection{Simple usage} % % To convert an \Algobox\ program to input suitable for this package you just % have to: % % \begin{enumerate} % \item Copy the program from the \string"Tester l'algorithme\string" % window and remove the line numbers. % \item Add \cs{;} at the end of each line (or at the beginning of each line % if like me you prefer to have those out of the way). The reason is that % some constructs in \Algobox\ programs depend on the line cuts whereas % \TeX\ treats those as normal spaces by default. Of course, one can setup % \TeX\ so that it temporarily obeys lines, but it \emph{cannot work} if % the algorithm is between braces (if you put in in a macro like % \cs{fbox}). % \item Add a backslash at the beginning of all \Algobox\ keywords, like % "VARIABLES", "SI", "DEBUT_SINON" and so on. % \item Remove all underscores in \Algobox\ keywords. You probably want to % remove them in all cases because \Algobox\ programs are not typeset in % math mode and \TeX\ will complain that you tried to use a subscript. If % you really want an underscore, replace it by \cs{_} \emph{but not in % keywords} or they will not be recognized anymore. % \item Put everything between "\begin{algobox}" and % "\end{algobox}". % \end{enumerate} % % Here is an example of the result: % % \begin{verbatim} % \begin{algobox} % \; \VARIABLES % \; a1 \ESTDUTYPE NOMBRE % \; b1 \ESTDUTYPE NOMBRE % \; a2 \ESTDUTYPE NOMBRE % \; b2 \ESTDUTYPE NOMBRE % \; \DEBUTALGORITHME % \; \LIRE a1 % \; \LIRE b1 % \; \LIRE a2 % \; \LIRE b2 % \; \SI (a1 == a2) \ALORS % \; \DEBUTSI % \; \SI (b1 == b2) \ALORS % \; \DEBUTSI % \; \AFFICHER "Les droites sont parallèles" % \; \FINSI % \; \SINON % \; \DEBUTSINON % \; \AFFICHER "Les droites sont sécantes" % \; \FINSINON % \; \FINSI % \; \SINON % \; \DEBUTSINON % \; \AFFICHER "Les droites sont confondues" % \; \FINSINON % \; \FINALGORITHME % \end{algobox} % \end{verbatim} % % The spacing is only for your convenience as \TeX\ treats any number of % consecutive spaces as a single one. % % Typesetting the previous example gives: % % \begin{algobox} % \def"{\string"} % \; \VARIABLES % \; a1 \ESTDUTYPE NOMBRE % \; b1 \ESTDUTYPE NOMBRE % \; a2 \ESTDUTYPE NOMBRE % \; b2 \ESTDUTYPE NOMBRE % \; \DEBUTALGORITHME % \; \LIRE a1 % \; \LIRE b1 % \; \LIRE a2 % \; \LIRE b2 % \; \SI (a1 == a2) \ALORS % \; \DEBUTSI % \; \SI (b1 == b2) \ALORS % \; \DEBUTSI % \; \AFFICHER "Les droites sont parallèles" % \; \FINSI % \; \SINON % \; \DEBUTSINON % \; \AFFICHER "Les droites sont sécantes" % \; \FINSINON % \; \FINSI % \; \SINON % \; \DEBUTSINON % \; \AFFICHER "Les droites sont confondues" % \; \FINSINON % \; \FINALGORITHME % \end{algobox} % % The algorithm is typeset as a TikZ picture, so is not breakable between pages. % % You can of course put the environment in anything you deem fit, like a "\fbox" % for instance. Here is an example: % % \fbox{ % \begin{algobox} % \def"{\string"} % \; \VARIABLES % \; note \ESTDUTYPE NOMBRE % \; \DEBUTALGORITHME % \; \LIRE note % \; \SI (note<10) \ALORS % \; \DEBUTSI % \; \AFFICHER "Il y a encore du travail" % \; \FINSI % \; \AFFICHER "On ne se relâche pas" % \; \POUR j \ALLANTDE 1 \A 25 % \; \DEBUTPOUR % \; \AFFICHERCALCUL i+3 % \; \FINPOUR % \; \FINALGORITHME % \end{algobox} % } % % \subsection{Customizing the appearance} % % TODO % % \end{documentation} % % \begin{implementation} % % \section{\pkg{\ExplFileName} implementation} % % \begin{macrocode} %<*package> %<@@=algobox> % \end{macrocode} % % \begin{macrocode} \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} % \end{macrocode} % \begin{macrocode} \RequirePackage{xparse} \RequirePackage{environ} \RequirePackage{tikz} \ExplSyntaxOff \usetikzlibrary{calc} \ExplSyntaxOn \RequirePackage{xcolor} \int_new:N \l_@@_level_int % \end{macrocode} % The colors are defined in "algohighlighter.cpp" in the \Algobox\ source, % except for the tree lines color. The names here are the same, with "algobox" % prepended. % \begin{macrocode} \definecolor{algoboxarbre}{RGB}{146,146,146} \definecolor{algoboxColorStandard}{HTML}{000000} \definecolor{algoboxColorComment}{HTML}{606060} \definecolor{algoboxColorBloc}{HTML}{800000} \definecolor{algoboxColorCommande}{HTML}{0000CC} \definecolor{algoboxColorSi}{HTML}{800080} \definecolor{algoboxColorTantQue}{HTML}{DD6F06} \definecolor{algoboxColorPour}{HTML}{BB8800} \definecolor{algoboxColorFonction}{HTML}{9A4D00} \tikzset{ every~algobox/.style=, every~smalgobox/.style={baseline=(block.base)}, algobox~ligne/.style={ xshift=1em, text~depth=0pt, inner~xsep=0.1ex, inner~ysep=0.5ex }, algobox~arbre/.style={ultra~thick, color=algoboxarbre}, algobox~indentsymb/.style={x=1ex, y=0.6ex, color=algoboxarbre}, algobox~indent/.style={xshift=2em}, algobox~normal/.style={ font=\sffamily, color=algoboxColorStandard, }, algobox~commentaire/.style={ algobox~normal/.try, color=algoboxColorComment, }, algobox~commande/.style={ algobox~normal/.try, color=algoboxColorCommande, }, algobox~structure/.style={ font=\sffamily\bfseries, color=algoboxColorBloc }, algobox~sialors/.style={ algobox~structure/.try, color=algoboxColorSi, }, algobox~pour/.style={ algobox~structure/.try, color=algoboxColorPour, }, algobox~tantque/.style={ algobox~structure/.try, color=algoboxColorTantQue, }, algobox~fonctions/.style={ algobox~structure/.try, color=algoboxColorFonction, }, } % \end{macrocode} % \subsection{Formatting commands} % \begin{macrocode} \tl_new:N \l_@@_lastnode_tl \cs_new_protected:Nn \@@_block:nn { \node[algobox~ligne/.try, \tl_if_empty:nF{#1}{algobox~#1/.try}, anchor=north~west ] (block) at (A\int_use:N \l_@@_level_int |- H) {\vphantom{A}#2}; \draw[algobox~arbre/.try] (A\int_use:N \l_@@_level_int) -- (A\int_use:N \l_@@_level_int |- block.west) coordinate (A\int_use:N \l_@@_level_int) -- (block.west); \coordinate (H) at (block.south); \tl_set:Nn \l_@@_lastnode_tl {block} } \cs_new_protected:Nn \@@_indent:nn { \node[algobox~ligne/.try, \tl_if_empty:nF{#1}{algobox~#1/.try}, anchor=north~west ] (block) at (A\int_use:N \l_@@_level_int |- H) {\vphantom{A}#2}; \draw[algobox~arbre/.try] (A\int_use:N \l_@@_level_int) -- (A\int_use:N \l_@@_level_int |- H); \fill[algobox~indentsymb/.try] (A\int_use:N \l_@@_level_int |- block.west) +(0,-1) -- +(1,1) -- +(-1,1) -- cycle; \coordinate (H) at (block.south); \coordinate (T) at (A\int_use:N \l_@@_level_int |- H); \coordinate (A\int_use:N \l_@@_level_int) at (T); \int_incr:N \l_@@_level_int \coordinate[algobox~indent/.try] (A\int_use:N \l_@@_level_int) at (T); \tl_set:Nn \l_@@_lastnode_tl {block} } \cs_new_protected:Nn \@@_unindent: { \int_decr:N \l_@@_level_int } \cs_new_protected:Nn \@@_node:nn { \node[algobox~#1/.try, anchor=base~west, inner~xsep=0pt] (node) at (\l_@@_lastnode_tl.base~east) {#2}; \tl_set:Nn \l_@@_lastnode_tl {node} } % \end{macrocode} % \subsection{Parsing helpers} % \begin{macrocode} \cs_new_protected:Nn \@@_parseall:n { \tl_set:Nn \l_tmpa_tl {#1} \seq_set_split:NnV \l_tmpa_seq {\;} \l_tmpa_tl % Now build up the algorithm body, working around the few infix notations. \tl_clear:N \l_@@_body_tl \seq_map_variable:NNn \l_tmpa_seq \l_tmpa_tl { \tl_if_in:NnT \l_tmpa_tl {\ESTDUTYPE} { \tl_put_left:Nn \l_tmpa_tl {\@@_ESTDUTYPE:w} } \tl_if_in:NnT \l_tmpa_tl {\PRENDLAVALEUR} { \tl_put_left:Nn \l_tmpa_tl {\@@_PRENDLAVALEUR:w} } \tl_put_right:Nn \l_tmpa_tl { \; } \tl_put_right:NV \l_@@_body_tl \l_tmpa_tl } \tl_use:N \l_@@_body_tl } \bool_new:N \l_@@_balanced_first_bool \cs_new_protected:Npn \@@_new_balanced_command:nNNnn #1#2#3 { \cs_new_protected:cpn {#1} ##1 #2 { \tl_set:Nn \l_@@_prefix_tl { ##1 } \tl_clear:N \l_@@_balanced_tl \bool_set_true:N \l_@@_balanced_first_bool \use:c {#1_stage2} #2 } \cs_new_protected:cpn {#1_stage2} ##1 #2 ##2 #3 { \tl_put_right:Nn \l_@@_balanced_tl { ##1 } \bool_if:NF \l_@@_balanced_first_bool { \tl_put_right:Nn \l_@@_balanced_tl { #2 } } \tl_if_in:nnTF {##2} {#2} { \bool_set_false:N \l_@@_balanced_first_bool \use:c {#1_stage2} ##2 \q_mark }{ \tl_put_right:Nn \l_@@_balanced_tl { ##2 } \tl_replace_all:Nnn \l_@@_balanced_tl {\q_mark} {#3} \tl_set:Nx \l_tmpa_tl { \exp_not:c {#1_stage3} \exp_not:V \l_@@_prefix_tl \exp_not:n {#2} { \exp_not:V \l_@@_balanced_tl } } \tl_use:N \l_tmpa_tl } } \exp_args:Nc \NewDocumentCommand {#1_stage3} } \cs_new_protected:Npn \@@_if_next:NTF #1#2#3 { \peek_meaning_remove_ignore_spaces:NTF \; { \@@_if_next:NTF #1 {#2} {#3} }{ \peek_meaning_remove_ignore_spaces:NTF \par { \@@_if_next:NTF #1 {#2} {#3} }{ \peek_meaning_ignore_spaces:NTF #1 {#2} {#3} } } } % \end{macrocode} % \subsection{Parsing/typesetting commands} % \begin{macrocode} \NewDocumentCommand \@@_ESTDUTYPE:w { +u{\ESTDUTYPE} +u{\;} } { \@@_block:nn {normal} { \ignorespaces #1 \unskip\c_space_token\null } \@@_node:nn {commande}{EST_DU_TYPE} \@@_node:nn {normal}{\null\c_space_token#2} } \NewDocumentCommand \@@_FINALGORITHME:w {} { \int_while_do:nNnn \l_@@_level_int > \c_zero_int { \@@_unindent: } \@@_block:nn {structure} {FIN_ALGORITHME} } \NewDocumentCommand \@@_PRENDLAVALEUR:w { u{\PRENDLAVALEUR} m } { \@@_block:nn {normal} { \ignorespaces#1\unskip\c_space_token\null } \@@_node:nn {commande}{PREND_LA_VALEUR} \@@_node:nn {normal}{\null\c_space_token#2} } \@@_new_balanced_command:nNNnn {@@_SI:w} \DEBUTSI \FINSI { r() u{\DEBUTSI} +m } { \@@_indent:nn {sialors} {SI} \@@_node:nn {normal}{\null\c_space_token(#1)\c_space_token\null} \@@_node:nn {sialors}{ALORS} \@@_block:nn {sialors} {DEBUT_SI} #3 \@@_block:nn {sialors} {FIN_SI} \@@_if_next:NTF \SINON { \@@_SINON:w }{ \@@_unindent: } } \@@_new_balanced_command:nNNnn {@@_SINON:w} \DEBUTSINON \FINSINON { u{\DEBUTSINON} +m } { \@@_indent:nn {sialors} {SINON} \@@_block:nn {sialors} {DEBUT_SINON} #2 \@@_block:nn {sialors} {FIN_SINON} \@@_unindent: \@@_unindent: } \@@_new_balanced_command:nNNnn {@@_POUR:w} \DEBUTPOUR \FINPOUR { u{\ALLANTDE} u{\A} u{\DEBUTPOUR} +m } { \@@_indent:nn {pour} {POUR} \@@_node:nn {normal}{\null\c_space_token #1\unskip\c_space_token\null} \@@_node:nn {pour}{ALLANT_DE} \@@_node:nn {normal}{\null\c_space_token #2\unskip \c_space_token A~#3\unskip\c_space_token\null} \@@_block:nn {pour} {DEBUT_POUR} #4 \@@_block:nn {pour} {FIN_POUR} \@@_unindent: } \@@_new_balanced_command:nNNnn {@@_TANTQUE:w} \DEBUTTANTQUE \FINTANTQUE { r() u{\DEBUTTANTQUE} +m } { \@@_indent:nn {tantque} {TANT_QUE} \@@_node:nn {normal}{\null\c_space_token(#1)\c_space_token\null} \@@_node:nn {tantque}{FAIRE} \@@_block:nn {tantque} {DEBUT_TANT_QUE} #3 \@@_block:nn {tantque} {FIN_TANT_QUE} \@@_unindent: } \NewDocumentCommand \@@_FONCTION:w { +u{\;} } { \int_while_do:nNnn \l_@@_level_int > \c_one_int { \@@_unindent: } \@@_indent:nn {fonctions} {FONCTION} \@@_node:nn {normal}{\null\c_space_token#1} } \NewDocumentCommand \@@_LINE:w { s O{normal} m } { \IfBooleanTF {#1} { \@@_indent:nn {#2} {#3} \@@_unindent: }{ \@@_block:nn {#2} {#3} } } \NewDocumentCommand \@@_NODE:w { O{normal} m } { \@@_node:nn {#1} {#2} } % \end{macrocode} % \subsection{User commands and environment} % \begin{macrocode} \cs_new_protected_nopar:Nn \@@_make_keyword:n { \tl_set:Nn \l_tmpa_tl {#1} \tl_replace_all:Nnn \l_tmpa_tl {_} {} \cs_set:cpn {\l_tmpa_tl} {\@@_keyword:nw {#1}} } \NewDocumentCommand \@@_keyword:nw {m +u{\;}} { \@@_block:nn {commande} {#1} \@@_node:nn {normal}{\null\c_space_token#2} } \cs_new_protected_nopar:Nn \@@_make_structure:nn { \tl_set:Nn \l_tmpa_tl {#2} \tl_replace_all:Nnn \l_tmpa_tl {_} {} \cs_set:cpn {\l_tmpa_tl} {\@@_topstructure:nn {#1}{#2}} } \cs_new_protected_nopar:Nn \@@_topstructure:nn { \int_while_do:nNnn \l_@@_level_int > \c_zero_int { \@@_unindent: } \@@_indent:nn {#1} {#2} } \cs_new_protected_nopar:Nn \@@_make_func_structure:nn { \tl_set:Nn \l_tmpa_tl {#1} \tl_replace_all:Nnn \l_tmpa_tl {_} {} \cs_set:cpn {\l_tmpa_tl} {\@@_funcstructure:nn {#1}{#2}} } \cs_new_protected_nopar:Nn \@@_funcstructure:nn { \int_while_do:nNnn \l_@@_level_int > { 2 } { \@@_unindent: } \bool_if:nTF {#2}{\@@_indent:nn}{\@@_block:nn} {fonctions} {#1} } \clist_const:Nn \c_@@_keywords_clist { PAUSE, LIRE, AFFICHERCALCUL, AFFICHER, TRACER_POINT, TRACER_POINT_Rouge, TRACER_POINT_Vert, TRACER_POINT_Bleu, TRACER_POINT_Blanc, TRACER_SEGMENT, TRACER_SEGMENT_Rouge, TRACER_SEGMENT_Vert, TRACER_SEGMENT_Bleu, TRACER_SEGMENT_Blanc, RENVOYER, APPELER_FONCTION } \cs_new_protected_nopar:Nn \@@_begincode:n { \int_zero:N \l_@@_level_int \begin{tikzpicture}[#1] \coordinate (H) at (0,0); \coordinate (A\int_use:N \l_@@_level_int) at (0,0); \cs_set_eq:NN \par \prg_do_nothing: \cs_set_eq:NN \; \prg_do_nothing: \cs_set_eq:NN \LINE \@@_LINE:w \cs_set_eq:NN \NODE \@@_NODE:w \cs_set_eq:NN \FINALGORITHME \@@_FINALGORITHME:w \cs_set_eq:NN \SI \@@_SI:w \cs_set_eq:NN \POUR \@@_POUR:w \cs_set_eq:NN \TANTQUE \@@_TANTQUE:w \cs_set_eq:NN \FONCTION \@@_FONCTION:w \cs_set:Npn \//##1\; {\@@_block:nn{commentaire}{//##1}} \clist_map_function:NN \c_@@_keywords_clist \@@_make_keyword:n \@@_make_structure:nn {structure} {VARIABLES} \@@_make_structure:nn {structure} {DEBUT_ALGORITHME} \@@_make_structure:nn {fonctions} {FONCTIONS_UTILISEES} \@@_make_func_structure:nn {VARIABLES_FONCTION} \c_true_bool \@@_make_func_structure:nn {DEBUT_FONCTION} \c_false_bool \@@_make_func_structure:nn {FIN_FONCTION} \c_false_bool } \cs_new_protected_nopar:Nn \@@_closecode: { \end{tikzpicture} } \NewDocumentCommand \smalgobox { O{} m } { \group_begin: \@@_begincode:n {every~smalgobox/.try,#1} \@@_parseall:n {#2} \@@_closecode: \group_end: } \NewDocumentEnvironment {algobox} {O{}} { \cs_set_protected:Nn \@@_algobox:n { \@@_begincode:n {every~algobox/.try,#1} \@@_parseall:n {##1} \@@_closecode: } \Collect@Body\@@_algobox:n }{ } % % \end{macrocode} % % \end{implementation}