Caspita. Mi sono completamente dimenticato che delle stringhe e i caratteri che possono contenere i simboli / /* //. Vabbè penso serva solo qualche aggiunta. (Inoltre ho visto che c'è un errore nel codice (o meglio ho inviato una versione non corretta). Il codice definitivo prevedeva di salvare il primo carattere in ch1 con la getchar prima del ciclo, la condizione del while non conteneva la getchar, che era inserita all'interno del ciclo. Dopo inserisco la correzione).
+m+ ha scritto:
mi pare serva una sistemata generale.
inizia a scrivere in pseudocodice come affronteresti il problema.
Per pseudocodice intendi un "codice in linguaggio generico" oppure di buttar giù a parole le idee per creare l'algoritmo? Te lo chiedo perchè quando si parla di pseudocodice vedo idee differenti (ad esempio per il prof del liceo i diagrammi di flusso li considerava come pseudocodice, anche se non sono sinonimi).
Inizio con una descrizione generica che mi sembra più semplice.
Innanzitutto avevo una scelta sull'acquisizione e il controllo del testo: leggere il flusso di caratteri così come veniva inserito ed operare carattere per carattere, oppure salvare ogni riga di input in un vettore di tipo char. Ho scelto la prima.
Poi mi sono chiesto come si riconosce un commento. Per i commenti in stile /* ... */ ci sono due caratteri che indicano dove inizia e due caratteri che indicano dove finisce, per le linee commentate i due caratteri // ne indicano l'inizio, mentre il carattere di newline ne indica la fine.
Il programma avrebbe dovuto stampare un carattere per volta fin quando non si fosse presentata la condizione di inizio di un commento, per poi ignorare i caratteri fin quando non si fosse presentata la condizione di fine commento. Per la condizione avrei potuto opzionalmente creare una variabile che mi indicasse lo stato (fuori dal commento/dentro il commento), cosa che non ho fatto.
Quindi abbiamo un ciclo che legge i caratteri volta per volta fin quando non viene inserito il carattere EOF.
All'interno del ciclo posso essere sicuro di poter stampare il carattere di quell'iterazione se il carattere è diverso da '/', perchè in quel caso sono sicuro che non sta iniziando un commento, a quel punto posso leggere il prossimo carattere.
Quando si presenta il carattere '/' potrei essere di fronte alla condizione di inizio commento oppure no, ciò dipende dal secondo carattere, per cui, se il secondo carattere non corrisponde nè a '*' (commento vecchio stile) nè a '/' (linea di commento), vuol dire che era un "falso allarme", posso allora stampare il primo carattere e salvare il secondo carattere per utilizzarlo al ciclo successivo.
Se invece il secondo carattere indica l'inizio di un commento, controllo se è '*' oppure '/'.
Nel primo caso opero con due variabili che indicano due caratteri consecutivi, in questo modo posso controllare quando ricevo l'indicazione di fine commento: fin quando la condizione non è verificata, prese due variabili che contengono i primi due caratteri consecutivi, sposto il secondo nella prima variabile e nella seconda variabile metto il prossimo carattere; una volta raggiunta la condizione di fine commento salvo il primo carattere dopo il commento per utilizzarlo al ciclo successivo.
Nel secondo caso mi basta leggere ed ignorare i caratteri fin quando non incontro quello di newline.
Ora, per quanto riguarda la parte mancante, basterà creare una condizione tipo testo_si/testo_no, ossia una sorta di valore booleano che mi dice quando mi trovo all'interno di una stringa oppure di un carattere, nel qual caso devo solo stampare carattere per carattere senza poter attivare le altre condizioni.
oregon ha scritto:
Ma hai provato il tuo programma? Funziona? Hai avuto problemi particolari?
L'ho provato con un paio di codici e a parte il fatto di essermi dimenticato della questione stringhe sembra funzionare. In effetti in origine avevo tentato un altro approccio che mi stava incasinando (fondamentalmente consideravo troppe variabili insieme senza procedere "a pezzettini" con il ragionamento) e presentava. Quando poi mi sono reso conto che stavo procedendo più per prova ed errore correggendo bug e aver perso di vista l'impostazione globale ho fatto ordine e, tutto sommato, mi piace abbastanza (almeno per il fatto che alla fine sono riuscito a "pianificare" anzichè andare a tentativi, poi per il codice in se ho bisogno del parere degli esperti, visto che ho solo da imparare).
Ah dimenticavo. Il codice giusto (senza la questione stringhe) è questo
#include <stdio.h>
int stampa_primo(void);
int stampa_secondo(void);
int canc_comm_1(void);
int canc_comm_2(void);
int ch1, ch2;
int main(void)
{
ch1 = getchar();
while (ch1 != EOF) { /* Controllo che il caratterenon sia uguale a EOF */
if (ch1 != '/') /* Se non può iniziare un commento stampo ch1 e prendo il seguente carattere */
stampa_primo(); /* per l'iterazione successiva */
else { /* Altrimenti, se il secondo carattere non fa iniziare un commento,*/
ch2 = getchar(); /* stampo il carattere e prendo il secondo per l'iterazione seguente */
if ( (ch2 != '/') && (ch2 != '*') )
stampa_secondo();
else if (ch2 == '*') /* Altrimenti controllo che tipo di commento è e chiamo la relativa funzione */
canc_comm_1();
else if (ch2 == '/')
canc_comm_2();
}
}
return 0;
}
/* Stampa il primo caratteree salva il prossimo nella variabile ch1 */
int stampa_primo(void)
{
putchar(ch1);
ch1 = getchar();
return 0;
}
/* Controlla se il secondo carattere dà inizio ad un commento. In caso negativo stampa il primo, */
/* salva il secondo nel primo e restituisce il controllo all'iterazione successiva*/
int stampa_secondo(void)
{
putchar(ch1);
ch1 = ch2;
return 0;
}
/* Ignora tutti i caratteri all'interno del commento vecchio stile */
int canc_comm_1(void)
{
ch1 = getchar();
ch2 = getchar();
while ( (ch1 != '*') || (ch2 != '/') ) { /* controlla quando i due caratteri indicano la fine di un commento */
ch1 = ch2;
ch2 = getchar();
}
ch1 = getchar();
return 0;
}
/* Ignora tutti i caratteri all'interno del commento nuovo stile */
int canc_comm_2(void)
{
while ( (ch1=getchar()) != '\n' )
;
return 0;
}