Newsgroup: it.comp.software.tex
Titolo: algoritmi [876896]

Ho provato vari pacchetti, ma non me n'č piaciuto neanche uno.
Ho scritto questo breve codice che fa tutto e solo ciň che mi serve:
(notate che da "if ok" fino a "\endgroup" gli spazi a inizio riga sono TAB).
 >>>>>>>>>
\begingroup
\catcode`\^^I=\active%
\catcode`\^^M=\active%
\def^^I{\hspace*{1\jot} $_.^.$ \hspace*{1\jot}}%
\def^^M{\\}%
\noindent%
if ok
	this
	that
	these
	those
		ytftyf
			gyuuyg
		pok
	opij
\endgroup
<<<<<<<<<
Adesso vorrei definire un ambiente "freecode", ma qui sorgono i 
problemi. Ho provato anche con "\let", ma la compilazione non va a buon 
fine. Non sapendo esattamente come vengono espanse le macro, posso solo 
ipotizzare che il problema sia che ^^I e ^^M diventano attivi non appena 
TeX incontra la definizione, cosa che ovviamente non voglio. Inoltre non 
ho idea di come TeX si comporti in presenza di \def annidati. La 
documentazione scarseggia...e il tempo anche.
Kiuhnm

 documentazione scarseggia...e il tempo anche.
\begingroup
\catcode`\^^I=\active
\def\x{\endgroup\def^^I{\makebox[2em]{$_.^.$}}}\x
\newenvironment{freecode}
  {\par\medskip\obeylines\catcode`\^^I=\active
   \setlength{\parindent}{0pt}}
  {\par\medskip}
Le prime tre righe servono per dare un significato al carattere <TAB>
quando è attivo. Non serve definire ^^M, basta dare \obeylines che rende
^^M attivo ed equivalente a \par; azzerando \parindent si ottiene il
risultato desiderato.
Quei due punti in quel modo mi piacciono poco, ma sono affari tuoi. :)
Ciao
Enrico

 Quei due punti in quel modo mi piacciono poco, ma sono affari tuoi. :)
Domani leggo con calma la tua risposta. Intanto (mi prenoto già per 
domani!), ti chiedo se è possibile sostituire i due punti con una linea 
verticale, ma non spezzata.
Kiuhnm

Kiuhnm scrive:

\begingroup
\catcode`\^^I=\active
\def\x{\endgroup\def^^I{\makebox[2em]{\strut\vrule}}}\x
\newenvironment{freecode}
  {\par\medskip\obeylines\everypar{\strut}\catcode`\^^I=\active
   \setlength{\parindent}{0pt}}
  {\par\medskip}
Se nessuna riga è particolarmente profonda o alta, le linee
verticali si dovrebbero sempre unire l'una all'altra.
Nel gruppo che comincia alla prima riga si definisce la macro \x il cui 
scopo è di chiudere il gruppo dove <TAB> è attivo e di definire il
significato di <TAB> attivo. Quando si esegue \x, il gruppo viene
chiuso e quindi <TAB> non sarà più attivo, ma il suo codice di
categoria era 13 (attivo) quando \x è stata definita.
Un altro modo, più facile da capire, sarebbe di scrivere
\begingroup
\catcode`\^^I=\active
\gdef^^I{...}
\endgroup
Il trucco di prima evita la definizione globale.
Quando si comincia l'ambiente freecode, viene dato un \par per
sicurezza e poi un \medskip; quindi rendiamo attivo ^^M e il suo
significato in LaTeX è \par. Ogni successivo capoverso (cioè ogni
riga dell'input) comincia con un comando \strut, in modo che altezza
e profondità di ciascuna riga sia la stessa. Quindi rendiamo ^^I
attivo e impostiamo il rientro a zero.
La definizione di ^^I è: lascia uno spazio di 2em, al centro del quale 
c'è una linea verticale alta e profonda come uno \strut (in italiano
si chiama "puntello").
Alla chiusura dell'ambiente tutte le impostazioni stabilite all'interno
spariscono. Per ultimo diamo un \par e un altro \medskip per simmetria.
Le linee sono per esercizio, io non le metterei affatto.
Ciao
Enrico

   {\par\medskip}
\par e \\ \\ sono equivalenti?
Kiuhnm

 \par e \\ \\ sono equivalenti?
Certo che no: \\ non chiude un capoverso.
Ciao
Enrico

 Le linee sono per esercizio, io non le metterei affatto.
Il codice potrebbe trovarsi a cavallo tra due pagine e quindi venire 
spezzato. Sarebbe alquanto difficile capire il livello d'indentazione 
della seconda parte senza qualche aiuto.
Ho anche pensato che forse, usando congiuntamente contatori ed 
etichette, si potrebbero aggiungere i ":" solo a fine e inizio pagina, 
ma poi ho accantonato l'idea per motivi di tempo.
Per la cronaca, io *voglio* che il codice venga spezzato quando 
necessario, perché è parte integrante di un discorso e non costituisce 
il classico algoritmo da esibire come risultato a sé stante.
Mentre scrivevo una dimostrazione mi sono reso conto che in inglese (o 
in italiano) non era facile essere abbastanza precisi e un elenco 
puntato non era abbastanza "strutturato" in quanto il metodo andava 
applicato ricorsivamente. Allora ho pensato di scrivere un algoritmo. 
Volevo però che restasse parte integrante del testo.
Kiuhnm

 Certo che no: \\ non chiude un capoverso.
Uno no, ma due? L'effetto non è lo stesso?
Kiuhnm

 Volevo però che restasse parte integrante del testo.
Prova a vedere che cosa salta fuori; se non ti va, basta togliere
\strut\vrule dal \makebox.
Ciao
Enrico

 Uno no, ma due? L'effetto non è lo stesso?
Naturalmente no. Il secondo \\ ha l'effetto di produrre un messaggio
di avviso di Underfull \hbox o, in certi casi, un messaggio di errore. 
Non si deve usare /mai/ \\ per terminare un capoverso, il suo uso va 
limitato, salvo casi particolarissimi, agli ambienti dove è necessario: 
tabular, array, flushleft, flushright, center e pochi altri.
Ciao
Enrico

 \strut\vrule dal \makebox.
Lo so, Enrico. Non sono solito copiare e usare codice che non capisco ;-)
Kiuhnm

 direttamente ^^M nel modo desiderato.
\begingroup
\catcode`\^^M=\active
\gdef\obeylinesprintingx{\catcode`\^^M=\active \def^^M{x\par}}
\endgroup
La versione senza \gdef è facile da scrivere:
\begingroup
\catcode`\^^M=\active
\def\x{\endgroup%
  \def\obeylinesprintingx{\catcode`\^^M=\active \def^^M{x\par}}}\x
Domandina: perché ci va % dopo \endgroup, mentre non è necessario
dopo \active?
Ciao
Enrico

 dopo \active?
Posso solo speculare.
Quando TeX arriva all'inizio del primo "\active", ^^M è ancora un 
carattere di categoria 10 e quindi viene assorbito da \active.
Ricordo infatti di aver dovuto aggiungere più volte '\ ' dopo un comando 
per ottenere uno spazio.
Quando la categoria di ^^M viene cambiata siamo già all'inizio della 
riga successiva. A questo punto è necessario usare '%' in modo che il 
carattere ^^M faccia parte del commento e venga quindi ignorato.
Kiuhnm

Kiuhnm scrive:

Esatto. Nel caso specifico non farebbe troppi danni, perché se non si
sono caricati pacchetti strani il valore di ^^M attivo è \par e,
siccome siamo in modo verticale, un \par non ha (quasi) alcun effetto.
Una versione più "sicura", perché dà a ^^M attivo un valore noto, è
\begingroup
\obeylines
\def\x{\endgroup%
  \def\obeylinesprintingx{\catcode`\^^M=\active \def^^M{x\par}}}\x%
e, in questo caso, i due % possono essere omessi proprio perché 
sappiamo che un \par non ha effetto. Ma è bene non trascurare i 
dettagli di questo tipo quando si è in regime di \obeylines. Il fine 
riga dopo \obeylines è irrilevante perché è già stato letto e scartato 
durante il procedimento di trasformazione in token (è un carattere di 
categoria 5 che segue un nome di comando, quindi sparisce) prima che 
sia espanso \obeylines e quindi prima che sia assegnata un diverso 
codice di categoria a ^^M.
Ciao
Enrico

 codice di categoria a ^^M.
Grazie per la spiegazione.
Quando hai tempo, potresti dare un'occhiata al seguente codice?
La modifica che ho apportato avrebbe dovuto far sì che TeX, a inizio 
pagina, mi stampasse delle piccole frecce (una per ogni tab), ma ho 
scoperto che la macro \thepage non ha il valore che mi sarei aspettato. 
Esiste una soluzione?
(Magari se si potesse eliminare anche la necessità di quel \blank...)
Kiuhnm
\newcommand{\IF} {\textbf{if}\hspace{2\jot}}
\newcommand{\ELSE} {\textbf{else}\hspace{2\jot}}
\newcommand{\printTab}{
	\ifnum \thelastpage=\thepage
	\else
		\tiny{$\to$}
	\fi
}
\newcounter{lastpage}
\setcounter{lastpage}{\value{page}}
\begingroup
\catcode`\^^I=\active
\def\x{\endgroup\def^^I{\makebox[2em]{\printTab}}}\x
\begingroup
\catcode`\^^M=\active
\def\x{\endgroup%
     \def\myobeylines{\catcode`\^^M=\active 
\def^^M{\setcounter{lastpage}{\value{page}}\par}}}\x
\newenvironment{freecode}
   {\par\medskip\myobeylines\catcode`\^^I=\active
    \setlength{\parindent}{0pt}}
   {\par\medskip}
\newcommand{\blank}{\phantom{m}}
\begin{freecode}
addArrows($x_i$, $y_j$)
	\IF $x_i < y_j$
		\IF $\nexists x_{i+1} \vee x_{i+1} > y_j$
			add arrow $y_j \to x_i$
	\ELSE
		\IF $\nexists y_{j+1} \vee y_{j+1} > x_i$
			add arrow $x_i \to y_j$
\blank
	// \emph{Recursive calls.}
	\IF $\exists x_{i+1} \wedge \exists y_{j+1}$
		\IF $x_{i+1} < y_{j+1}$
			addArrows($x_{i+1}$, $y_j$)
		\ELSE
			addArrows($x_i$, $y_{j+1}$)
	\ELSE \IF $\exists x_{i+1}$
		addArrows($x_{i+1}$, $y_j$)
	\ELSE \IF $\exists y_{j+1}$
		addArrows($x_i$, $y_{j+1}$)
\end{freecode}

Kiuhnm scrive:

Userei \medskip invece di \blank, se tutto ciò che vuoi è una riga 
vuota.  Se vuoi uno spazio dopo \IF, perché non definire
\newcommand{\IF}{\textbf{if}\ }
invece di usare \jot che è del tutto fuori posto là? Io scriverei 
\newcommand{\IF}{\textbf{if}} e poi "\IF\ " nel documento.
C'è un grave errore concettuale, prima di tutto. Se il codice 
funzionasse, ti troveresti tutto il testo dell'ambiente freecode 
dopo il cambio pagina scritto in corpo piccolissimo, perché \tiny 
compare fuori da un gruppo: non è un comando con un argomento, ma
una dichiarazione. Più semplicemente puoi dire $\scriptstyle\to$ o,
se vuoi una freccia ancora più piccola, $\scriptscriptstyle\to$.
Ma il codice così com'è non può funzionare, perché il numero di pagina
viene modificato /dopo/ che la riga che deve andare alla nuova pagina
è già stata composta. È la routine di output che assegna il nuovo
numero e solo quando è stato accumulato più materiale di quello che
sta in una pagina la routine viene invocata.
Quindi il tuo test produrrà le freccette solo alcune righe più in giù
e (quasi) certamente non alla prima riga della nuova pagina. Aggiungiamo
un comando che ridefinisca \PrintTab alla routine di output? Non
servirebbe, perché ormai il primo capoverso della nuova pagina è già
stato composto.
Non dico che sia impossibile ottenere ciò che desideri, ma sinceramente
non ne vedo l'utilità. L'unico modo è di usare \label e \pageref. Ogni
comando ^^M dovrebbe definire una \label diversa e \PrintTab guardare
il valore di \pageref per prendere la decisione se stampare la freccia.
Nella documentazione del pacchetto ifthen è spiegato come fare.
Ciao
Enrico

 Nella documentazione del pacchetto ifthen è spiegato come fare.
Senza guardare ifthen (altrimenti che gusto c'è?) ho risolto come segue.
Note:
1) Scusami se ho lasciato alcune cose che non ti piacciono!
2) Prima dell'algoritmo viene lasciato uno spazio (verticale) che non mi 
spiego.
3) La settima riga genera un warning, ma poco male...
\newcommand{\IF} {\textbf{if}\hspace{2\jot}}
\newcommand{\ELSE} {\textbf{else}\hspace{2\jot}}
%
\newcounter{labelno}
\newcounter{prevlabelno}
\def\mylabel{\label{mylabel_\thelabelno}\setcounter{prevlabelno}{\value{labelno}}\stepcounter{labelno}}
\def\mypageref{\pageref{mylabel_\theprevlabelno}}
%
\newcounter{firstTab}
\setcounter{firstTab}{1}
\newcommand{\printTab}{
	\mylabel
	\ifnum \thelastpage=\mypageref
	\else
		\tiny{$\to$}
	\fi
}
%
\newcounter{lastpage}
\setcounter{lastpage}{\mypageref}
%
\begingroup
\catcode`\^^I=\active
\def\x{\endgroup\def^^I{\makebox[2em]{\printTab}}}\x
%
\begingroup
\catcode`\^^M=\active
\def\x{\endgroup%
     \def\myobeylines{\catcode`\^^M=\active 
\def^^M{\setcounter{lastpage}{\mypageref}\par}}}\x
%
\newenvironment{freecode}
     {\par\medskip\myobeylines\catcode`\^^I=\active
         \setlength{\parindent}{0pt}}
     {\par\medskip}
%
\begin{freecode}
addArrows($x_i$, $y_j$)
	\IF $x_i < y_j$
		\IF $\nexists x_{i+1} \vee x_{i+1} > y_j$
			add arrow $y_j \to x_i$
	\ELSE
		\IF $\nexists y_{j+1} \vee y_{j+1} > x_i$
			add arrow $x_i \to y_j$
\medskip
	// \emph{Recursive calls.}
	\IF $\exists x_{i+1} \wedge \exists y_{j+1}$
		\IF $x_{i+1} < y_{j+1}$
			addArrows($x_{i+1}$, $y_j$)
		\ELSE
			addArrows($x_i$, $y_{j+1}$)
	\ELSE \IF $\exists x_{i+1}$
		addArrows($x_{i+1}$, $y_j$)
	\ELSE \IF $\exists y_{j+1}$
		addArrows($x_i$, $y_{j+1}$)
\end{freecode}
Kiuhnm

 \setcounter{firstTab}{1}
Non ho ripulito il codice. Alcune cose non servono...
Kiuhnm

 3) La settima riga genera un warning, ma poco male...
Non ho alcun warning. Inoltre non devi affatto impostare il
valore di lastpage appena lo definisci, visto che, fra l'altro,
dà un errore.
È esattamente l'idea che ti avevo suggerito. Il pacchetto ifthen
mette a disposizione qualcosa che evita i messaggi di errore quando
il file .aux non c'è o hai appena aggiunto l'ambiente.
Ciao
Enrico

 il file .aux non c'è o hai appena aggiunto l'ambiente.
Cioè quando il file .aux non c'è o non è aggiornato, immagino.
Per motivi di memoria, ho modificato il codice in modo che venga 
aggiunta una sola label per riga.
Kiuhnm

 A me non dą nessun errore, a dire il vero. Puoi spiegarti meglio?
Ho capito: "\setcounter{lastpage}{\mypageref}" dą errore se si trova 
prima di \begin{document}, per motivi facilmente intuibili.
Kiuhnm

 Cioè quando il file .aux non c'è o non è aggiornato, immagino.
Infatti: \setcounter{lastpage}{\xyz} funziona solo se \xyz si espande
a un numero, altrimenti dà un ovvio errore; il tuo comando si espande
a un numero di pagina solo se l'etichetta è stata definita e questo
ovviamente non può funzionare.
Siccome sappiamo che \pageref{etichetta} si espande comunque a qualcosa
di stampabile, un modo per vedere se l'espansione è un numero è di
scrivere
\setbox0=\hbox{\count255=\number0\pageref{etichetta}}%
\ifdim\wd0=0pt
  \setcounter{lastpage}{\pageref{etichetta}}% è un numero
\else
  \setcounter{lastpage}{-1}% non è un numero, uso un valore fittizio
\fi
Infatti, se \pageref{etichetta} si espande a un numero, questo viene
mangiato dall'assegnazione al contatore \count255, non lasciando nulla
nella \hbox; se invece si espande ai soliti due punti interrogativi
perché "etichetta" non è ancora definita, la \hbox non sarà vuota.
Ma il problema si ha solo alla prima compilazione dopo che hai
aggiunto un ambiente freecode, in tal caso basta rispondere con
invio a ogni errore; il documento verrà "sbagliato", ma la volta
successiva sarà corretto.
Un'altra cosa: non userei \ifnum\thepage=\thelastpage, perché ciò
può darti problemi nel caso il numero di pagina non sia un numero
in cifre arabe. Meglio
\ifnum\value{page}=\value{lastpage}
che prescinde dalla rappresentazione dei contatori. Se uno dei tuoi
algoritmi finisse nel "frontmatter" dove le pagine sono numerate in
cifre romane saresti nei pasticci.
Ciao
Enrico

 cifre romane saresti nei pasticci.
Giusto.
Kiuhnm

Enrico Gregorio wrote:
[...]
Grazie infinitamente per l'aiuto e la pazienza!
Ciao, Kiuhnm