[C] Eliminare commenti da un file sorgente in C

Linguaggi di programmazione: php, perl, python, C, bash e tutti gli altri.
gila75
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2739
Iscrizione: mercoledì 16 gennaio 2013, 17:28
Desktop: ubuntu-2d
Distribuzione: Ubuntu 12.04.2 LTS i686
Località: Airuno(Lecco)

Re: [C] Eliminare commenti da un file sorgente in C

Messaggio da gila75 »

Secondo me è un problema molto complesso in fase di studio base del c
Non so se vale la pena.mi sembrano cose che dovrebbero venire dopo
sbam
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 305
Iscrizione: giovedì 11 dicembre 2014, 20:31

Re: [C] Eliminare commenti da un file sorgente in C

Messaggio da sbam »

Intendo righe di programma, se apro gli apici e vado a caporiga, quello che scrivo e' inteso come fuori dalla stringa.

Codice: Seleziona tutto

char s[] = "All'interno della stringa
// è un commento, nonostante non ci sia stato un " di chiusura
Se provi a spostarlo in un editor "a colori", per esempio quello di Code::Blocks, si vede che la stringa continua per tutta la prima riga ma la seconda è commento, la "definizione" non può durare più di una riga.
Immagine
Avatar utente
vbextreme
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1214
Iscrizione: domenica 12 gennaio 2014, 14:06
Desktop: lxde
Distribuzione: xubuntu 14.10

Re: [C] Eliminare commenti da un file sorgente in C

Messaggio da vbextreme »

io farei un automa come in allegato.

che trasformato in codice salta fuori una cosa tipo questa:

Codice: Seleziona tutto

#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio_ext.h>
#include <time.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
#include <errno.h>
#include <stdbool.h>
 
#if _DEBUG
void waitenter()
{
    printf("wait enter");
    char c[80];
    fgets(c,80,stdin);
}
#endif
 
 
 
 
#define MAXSTACK 1024
static char stk[MAXSTACK];
static int  istk = 0;

int push(char c)
{
    if ( istk >= MAXSTACK ) return -1;
    stk[istk++] = c;
    return 0;
}
    
int pop(void)
{
    if ( istk <= 0 ) return  -1;
    return stk[--istk];
}

/**********************************************************************/

typedef struct _RWFILE
{
    FILE* r;
    FILE* w;
}RWFILE;

int rwopen(RWFILE* f, char* source, char* dest)
{
    f->r = fopen(source,"r");
        if ( NULL == f->r ) return -1;
    f->w = fopen(dest,"w");
        if ( NULL == f->w ) { fclose(f->r); return -2;}
    return 0;
}

#define rwgetc(F)   ({ int c = fgetc(F->r); c; })
#define rwputc(C,F) ({ if ( C != EOF ) fputc(C, F->w); })

int rwclose(RWFILE* f)
{
    fclose(f->r);
    fclose(f->w);
    return 0;
}

/**********************************************************************/

typedef int(*state_f)(RWFILE*, int);
typedef enum { _S, _A, _B, _C, _D, _E, _F, _Z, _COUNT} state_e;
 
static state_e stateautomata = 0;

int automata_S(RWFILE* f, int c)
{
    if ( c == '/' )
    {
        stateautomata = _A;
    }
    else if ( c == '\"' )
    {
        push(c);
        rwputc(c, f);
        stateautomata = _F;
    }
    else if ( c == EOF )
    {
        stateautomata = _E;
    }
    else
    {
        rwputc(c, f);
    }
    return 0;
}

int automata_A(RWFILE* f, int c)
{
    if ( c == '/' )
    {
        stateautomata = _B;
    }
    else if ( c == '*' )
    {
        push(c);
        stateautomata = _C;
    }
    else if ( c == EOF )
    {
        stateautomata = _E;
    }
    else
    {
        rwputc('/', f);
        rwputc(c, f);
        stateautomata = _S;
    }
    
    return 0;
}

int automata_B(RWFILE* f, int c)
{
    if ( c == '\n' )
    {
        rwputc(c, f);
        stateautomata = _S;
    }
    else if ( c == EOF )
    {
        stateautomata = _E;
    }
    
    return 0;
}

int automata_C(RWFILE* f, int c)
{
    if ( c == '*' )
    {
        stateautomata = _D;
    }
    else if ( c == EOF )
    {
        stateautomata = _Z;
    }
    
    return 0;
}

int automata_D(RWFILE* f, int c)
{
    if ( c == '/' )
    {
        if ( pop() != '*' ) return -1;
        stateautomata = _S;
    }
    else if ( c == EOF )
    {
        stateautomata = _Z;
    }
    else
    {
        stateautomata = _C;
    }
    return 0;
}


int automata_E(RWFILE* f, int c)
{
    return 1;
}

int automata_F(RWFILE* f, int c)
{
    if ( c == '"' )
    {
        if ( pop() != '"' ) return -1;
        stateautomata = _S;
    }
    else if ( c == EOF )
    {
        stateautomata = _Z;
    }
    rwputc(c, f);
    return 0;
}

int automata_Z(RWFILE* f, int c)
{
    return -1;
}

static state_f fncautomata[_COUNT] = { automata_S, automata_A, automata_B, automata_C, automata_D,
                                       automata_E, automata_F, automata_Z };

int automata_state(RWFILE* f)
{
    int c;
    int ret;
    do
    {
        c = rwgetc(f);
        
        #if _DEBUG
        printf("read :%c \n",c);
        printf("state:%d \n",stateautomata);
        #endif
        
        ret = fncautomata[stateautomata](f, c);
        
        #if _DEBUG
        printf("ret  :%d \n",ret);
        waitenter();
        #endif
        
    }while( 0 == ret );
    
    return ret;
}


int main(int argc, char** argv) 
{
    if ( argc != 3 )
    {
        fputs("source.c dest.c\n", stderr);
        return -7;
    }
    
    RWFILE rw;
    int ret = rwopen(&rw, argv[1], argv[2]);
        if ( ret == -1 ) { fputs("error to open source file\n", stderr); return -1; }
        if ( ret == -2 ) { fputs("error to open dest file\n", stderr); return -2; }
    
    ret = automata_state(&rw);
    rwclose(&rw);
    
    if ( ret != 1 )
    {
        fputs("error to parse file, incorrect close comment or close double quote\n",stderr);
        return -3;
    }
    
    return 0;
}

gli va passato il file di origine e quello di destinazione.
se compilate con "-D_DEBUG" potete vedere come funzionano i vari passaggi.

[edit]
nella linea che va da B a S manca il testo, non l'ha salvata quando ho esportato come jpg :muro: , il testo è
StartCpy()
'\n'
[/edit]
Allegati
automata.jpg
Easy framework per il linguaggio C.
vbextreme hack your life
sbam
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 305
Iscrizione: giovedì 11 dicembre 2014, 20:31

Re: [C] Eliminare commenti da un file sorgente in C

Messaggio da sbam »

Ma pop e' uguale farla ritornare char, no?
Avatar utente
crap0101
Rampante Reduce
Rampante Reduce
Messaggi: 8242
Iscrizione: martedì 30 ottobre 2007, 6:33
Desktop: LXDE
Distribuzione: Ubuntu 18.04.1 LTS
Sesso: Maschile
Località: TO
Contatti:

Re: [C] Eliminare commenti da un file sorgente in C

Messaggio da crap0101 »

sbam [url=http://forum.ubuntu-it.org/viewtopic.php?p=4851594#p4851594][img]http://forum.ubuntu-it.org/images/icons/icona-cita.gif[/img][/url] ha scritto:Intendo righe di programma, se apro gli apici e vado a caporiga, quello che scrivo e' inteso come fuori dalla stringa.

Codice: Seleziona tutto

char s[] = "All'interno della stringa
// è un commento, nonostante non ci sia stato un " di chiusura
Se provi a spostarlo in un editor "a colori", per esempio quello di Code::Blocks, si vede che la stringa continua per tutta la prima riga ma la seconda è commento, la "definizione" non può durare più di una riga.
Immagine
bè così però è proprio _sbagliato_, non è roba compilabile, io intendevo:

Codice: Seleziona tutto

crap0101@orange:/tmp/foo$ cat x.c
#include <stdio.h>
int main (void) {
    char s[] = "foo \
// è un commento, nonostante non ci sia stato un \" di chiusura \
bar \
baz \
";
    puts(s);
    return 0;
}
in cui la linea "commentata" non è un commento ma parte della stringa `s`.
http://www.gnu.org/ http://boinc.berkeley.edu/ http://www.python-it.org/
- Ricorda le ultime parole di suo padre: «Sta' alla larga dalle chiese, figlio. La sola cosa per cui hanno la chiave è il merdaio. E giurami che non porterai mai un distintivo della legge» - W.S. Burroughs
sbam
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 305
Iscrizione: giovedì 11 dicembre 2014, 20:31

Re: [C] Eliminare commenti da un file sorgente in C

Messaggio da sbam »

Non e' compito del programma controllare se sia corretto o meno :)
ixamit
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 499
Iscrizione: giovedì 14 novembre 2013, 10:16

Re: [C] Eliminare commenti da un file sorgente in C

Messaggio da ixamit »

Premetto che non e' il genere di esercizio che mi esalta, ma io semplificherei di brutto lavorando su un'unico buffer anziche' complicarmi la vita con blocchi o singole letture.
Per cui il _mio_ approccio "semplicistico" consiste nel preallocare un blocco sufficientemente grande per l'intero file, magari una sola lettura, per poi gestirmi gli stati e stampare tutto quello che non rientra nel REM su stdout.
Sinceramente non so se ho sbagliato qualcosa, magari nella zona "QUOTE", ma mi sono limitato a testatare i tempi su file decisamente grandicelli:

Codice: Seleziona tutto

max@studio:/tmp$ gcc -Wall -pedantic -O2 del.c -o del
max@studio:/tmp$ time ./del < /usr/include/GL/glew.h > glew.h

real	0m0.020s
user	0m0.012s
sys	0m0.004s
max@studio:/tmp$ time ./del < /usr/include/GL/glew.h > glew.h
max@studio:/tmp$

real	0m0.020s
user	0m0.012s
sys	0m0.004s
max@studio:/tmp$ wc /usr/include/GL/glew.h glew.h
  16126   61686  837247 /usr/include/GL/glew.h
  16038   57311  785065 glew.h
  32164  118997 1622312 totale
max@studio:/tmp$ 
max@studio:/tmp$ gcc -c glew.h
max@studio:/tmp$
codice:

Codice: Seleziona tutto

#include <stdio.h>

#define MAX_BUF 8000000 /* 8M */
#define ESCAPED (p>buf?*(p-1)=='\\'||*(p-1)=='\'':0)
char buf[MAX_BUF],*p,state;
enum {CODE,QUOTE,REM};

void skip_rem()
{
    p=buf;
    while(*p)
    {
        if (state==CODE&&*p=='/')
        {
            if (*(p+1)=='*') state=REM,p+=2;             /* REM C89 */
            else if (*(p+1)=='/') while(*++p&&*p!='\n'); /* REM C99 */
        }
        else if (state==REM&&*p=='*'&&*(p+1)=='/')
            state=CODE,p+=2; /*  BYE-BYE REM  */
        else if (state!=REM&&*p=='"'&&!ESCAPED)
            state=!state;    /* CODE<-->QUOTE */
        if (state!=REM)      /* CODE or QUOTE */ 
            putchar(*p);
        p++;
    }
}

int main(int argc, char **argv)
{
    if ((fread(buf, 1, MAX_BUF, stdin))==MAX_BUF)
        return fputs("fatal:buffer overflow!\n",stderr);

    skip_rem();
    if (state==QUOTE)  fputs("warning:unmatched quote!\n",stderr);
    else if (state==REM) fputs("warning:unmatched rem!\n",stderr);

    return (int)state;
}
fabio massacci
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 289
Iscrizione: mercoledì 11 giugno 2014, 14:12
Desktop: Lubuntu
Distribuzione: Ubuntu 20.04.3 LTS

Re: [C] Eliminare commenti da un file sorgente in C

Messaggio da fabio massacci »

@ixamit non uso spesso stdin associato a fread, ma se funziona come per i file normali (e dovrebbe essere così) allora il tuo buffer non non ha garanzie di avere un 0 finale.

Comunque sono d'accordo anche io per evitare tutte quelle scritture e/o letture piccole che fanno perdere tempo inutile in accessi al disco...

Codice: Seleziona tutto

(...)
FILE *f = fopen("il_tuo_file.c", "rb");
fseek(f, 0, SEEK_END);
long file_size = ftell(f);
fseek(f, 0, SEEK_SET);

if( file_size >= MASSIMA_LUNGHEZZA_FILE_PERMESSA ) {
	fclose(f);
	return;
}

fread(buffer, file_size, 1, f);
fclose(f);

buffer[file_size] = 0;

ecc...
EDIT: scusate ho editato il codicello un paio di volte
Ultima modifica di fabio massacci il mercoledì 10 febbraio 2016, 18:49, modificato 3 volte in totale.
ale4
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 761
Iscrizione: venerdì 10 agosto 2012, 17:53

Re: [C] Eliminare commenti da un file sorgente in C

Messaggio da ale4 »

Ma secondo me si fa prima a non usare un buffer, questa è la mia soluzione senza buffer usando solo due variabili char alla fine

Codice: Seleziona tutto

#include <stdio.h>
int main(){
  char ch, nextch;
  while ((ch=getchar())!=EOF) {
    if (ch=='/'){
      nextch = getchar();
      if (nextch=='/') {
        while (getchar()!='\n');
      } else if (nextch=='*') {
        ch = getchar();
        while (1) {
          if (ch=='*') {
            ch = getchar();
            if (ch=='/') break;
          } else {
            ch = getchar();
          }
        }
      } else {
        putchar(ch);
        putchar(nextch);
      }
    } else if (ch=='"') {
      putchar(ch);
      while ((ch=getchar())){
        putchar(ch);
        if (ch=='\\') putchar(getchar());
        if (ch=='"') break;
      }
    } else if (ch=='\'') {
      putchar(ch);
      while ((ch=getchar())){
        putchar(ch);
        if (ch=='\\') putchar(getchar());
        if (ch=='\'') break;
      }
    } else {
      putchar(ch);
    }
  }
  return 0;
}
Non sarà bellissima ne leggibilissima, ma funziona bene ed è stata relativamente veloce da scrivere (una decina di minuti) e funziona bene (provato su più file header in /usr/include e poi compilano bene), è anche veloce alla fine, probabilmente si può anche ottimizzare di più in certi punti anche, non ha limitazioni su quanto deve essere grosso il buffer e non consuma praticamente memoria dato che le uniche variabili che usa sono due char, e probabilmente è anche veloce dato che non deve gestire buffer e tutto
fabio massacci
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 289
Iscrizione: mercoledì 11 giugno 2014, 14:12
Desktop: Lubuntu
Distribuzione: Ubuntu 20.04.3 LTS

Re: [C] Eliminare commenti da un file sorgente in C

Messaggio da fabio massacci »

@ale4 guarda, non è che si voglia per forza leggere un file tutto insieme (ne tanto meno volevo per forza porre limiti al file), era per dare un'alternativa a quelli che ne vogliono leggere/scrivere pochi byte per volta, peggio ancora se parliamo di un byte per volta. Tu e ixamit usate i pipe quindi forse demandate al sistema operativo l'onere di decidere quanti byte per volta estrarre/scrivere dai file coinvolti, cosa che potrebbe fare in maniera più efficiente di noi, però magari anche lì se ad ogni putchar e ad ogni getchar corrisponde una richiesta diversa di accesso al disco(non è detto), be capisci da solo che è meno efficiente, preferisco allora leggere/scrivere il file un tot per volta ma dove quel tot sia almeno di diversi KB.

intendiamoci forse con il compito di questo post non vale la pena ottimizzare troppo ma fare le cose più velocemente non ha mai fatto troppo male
Avatar utente
vbextreme
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1214
Iscrizione: domenica 12 gennaio 2014, 14:06
Desktop: lxde
Distribuzione: xubuntu 14.10

Re: [C] Eliminare commenti da un file sorgente in C

Messaggio da vbextreme »

putchar e getchar sono bufferizzate.
In passato abbiamo già provato e il buffer di sistema è più veloce che la lettura totale del file in un colpo solo.
Easy framework per il linguaggio C.
vbextreme hack your life
ale4
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 761
Iscrizione: venerdì 10 agosto 2012, 17:53

Re: [C] Eliminare commenti da un file sorgente in C

Messaggio da ale4 »

Le pipe copiano i dati in blocco, nel caso di linux 4096byte o 4k, ossia una pagina di memoria alla fine, inoltre poi il kernel applica varie ottimizzazioni, quando apri un file anche con la chiamata di sistema open il kernel precaria in ram un tot di blocchi del file (non so quanti anche perché dipende dal kernel), perché prevede le letture successive per esempio, o usa altri algoritmi intelligenti per limitare le scritture su disco, previa ovviamente ram non utilizzata (ovviamente la memoria allocata dai programmi ha la priorità su quella allocata dalla cache dei file), insomma il kernel, linux in particolare, sotto questo aspetto è molto ottimizzato, e anche la libreria C lo è, infatti se il programma viene lanciato con output su una pipe non svuota il buffer ad ogni newline ma piuttosto lo svuota raggiunta la dimensione della pagina, ossia dopo 4096 byte

Puoi controllare comunque questo comportamento lanciando il programma con strace alla fine, vedi che le chiamate read e write sono esattamente da 4096 byte
fabio massacci
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 289
Iscrizione: mercoledì 11 giugno 2014, 14:12
Desktop: Lubuntu
Distribuzione: Ubuntu 20.04.3 LTS

Re: [C] Eliminare commenti da un file sorgente in C

Messaggio da fabio massacci »

si infatti questo lo immaginavo, comunque anche usando una pipe, preferisco usare una fread per riempire un buffer da, che so, 4096 byte e poi scorrerlo con un puntatore piuttosto che fare 4096 chiamate a getchar
ixamit
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 499
Iscrizione: giovedì 14 novembre 2013, 10:16

Re: [C] Eliminare commenti da un file sorgente in C

Messaggio da ixamit »

fabio masacci ha scritto: @ixamit non uso spesso stdin associato a fread, ma se funziona come per i file normali (e dovrebbe essere così) allora il tuo buffer non non ha garanzie di avere un 0 finale.
I dati allocati su .bss sono storicamente inizializzati a zero.
fabio massacci
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 289
Iscrizione: mercoledì 11 giugno 2014, 14:12
Desktop: Lubuntu
Distribuzione: Ubuntu 20.04.3 LTS

Re: [C] Eliminare commenti da un file sorgente in C

Messaggio da fabio massacci »

ixamit [url=http://forum.ubuntu-it.org/viewtopic.php?p=4851818#p4851818][img]http://forum.ubuntu-it.org/images/icons/icona-cita.gif[/img][/url] ha scritto:
fabio masacci ha scritto: @ixamit non uso spesso stdin associato a fread, ma se funziona come per i file normali (e dovrebbe essere così) allora il tuo buffer non non ha garanzie di avere un 0 finale.
I dati allocati su .bss sono storicamente inizializzati a zero.
si giusto mea culpa
Avatar utente
Vincenzo1968
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 450
Iscrizione: lunedì 14 gennaio 2013, 14:21
Desktop: Unity
Distribuzione: Ubuntu 18.04.3 LTS x86_64
Località: Villabate(PA)
Contatti:

Re: [C] Eliminare commenti da un file sorgente in C

Messaggio da Vincenzo1968 »

La mia soluzione:

Codice: Seleziona tutto

#define _FILE_OFFSET_BITS 64

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BLOCK_SIZE 4096

typedef enum tagStates
{
	S0,
	S1,
	S2,
	S3,
	S4,
	S5,
	S6,
	S7,
	S8
} States;

int makeOutput(const char *szFileName, const char *szNewFileName);

int makeOutput(const char *szFileName, const char *szNewFileName)
{
	int retValue = 1;
	
	FILE *fp = NULL;
	FILE *fpNew = NULL;
	unsigned char *myBlock = NULL;
	unsigned char *myBlockNew = NULL;
	
	int blockLen = 0;
	int index1 = 0;	
	int index2 = 0;
	
	States state = S0;
	char c;
	
	myBlock = (unsigned char *)malloc(sizeof(unsigned char) * BLOCK_SIZE);
	if ( !myBlock )
	{
		printf("Memoria insufficiente.\n");
		retValue = 0;
		goto uscita;
	}	
	
	myBlockNew = (unsigned char *)malloc(sizeof(unsigned char) * BLOCK_SIZE);
	if ( !myBlockNew )
	{
		printf("Memoria insufficiente.\n");
		retValue = 0;
		goto uscita;
	}	
	
	fp = fopen(szFileName, "rb");
	if ( fp == NULL )
	{
		printf("Errore nell'apertura del file '%s'.\n", szFileName);
		retValue = 0;
		goto uscita;
	}
	
	fpNew = fopen(szNewFileName, "wb");
	if ( fpNew == NULL )
	{
		printf("Errore nella creazione del file '%s'.\n", szNewFileName);
		retValue = 0;
		goto uscita;
	}		
	
	while ( (blockLen = fread(myBlock, 1, BLOCK_SIZE, fp)) )
	{
		index1 = 0;
		
		while ( index1 < blockLen )
		{		
			c = myBlock[index1++];
		
			switch ( state )
			{
				case S0:
					if ( c == '/' )
					{
						state = S1;
					}
					else if ( c == '"' )
					{
						myBlockNew[index2++] = c;					
															
						state = S2;
					}
					else if ( c == '\'' )
					{
						myBlockNew[index2++] = c;					
															
						state = S7;
					}					
					else
					{
						myBlockNew[index2++] = c;										
					}				
					break;
				case S1:
					if ( c == '*' )
					{
						state = S3;
					}
					else if ( c == '/' )
					{
						state = S4;
					}					
					else
					{
						myBlockNew[index2++] = c;										
					}
					break;
				case S2:
					myBlockNew[index2++] = c;					
															
					if ( c == '"' )
					{
						state = S0;
					}
					else if ( c == '\\' )
					{						
						state = S5;
					}
					break;
				case S3:
					if ( c == '*' )
					{					
						state = S6;
					}
					break;								
				case S4:				
					if ( c == '\r' || c == '\n' )
					{	
						myBlockNew[index2++] = c;
																										
						state = S0;
					}
					break;
				case S5:
					myBlockNew[index2++] = c;
											
					state = S2;
					break;
				case S6:
					if ( c == '/' )
					{					
						state = S0;
					}
					else
					{
						state = S3;
					}
					break;
				case S7:
					myBlockNew[index2++] = c;
					
					if ( c >= '\\' )
					{						
						state = S8;
					}
					else if ( c == '\'' )
					{
						state = S0;
					}				
					break;
				case S8:
					myBlockNew[index2++] = c;
					
					state = S7;
					break;																		
			} /* Fine switch */	
			
			if ( index2 >= BLOCK_SIZE )
			{
				fwrite(myBlockNew, 1, BLOCK_SIZE, fpNew);
				index2 = 0;
			}			
		}			
	}	
	
	if ( index2 > 0 )
		fwrite(myBlockNew, index2, 1, fpNew);	
	
uscita:
	if ( myBlock)
		free(myBlock);
	if (myBlockNew )
		free(myBlockNew);
	if ( fp )
		fclose(fp);
	if ( fpNew )
		fclose(fpNew);
	
	return retValue;
}

/*
gcc -Wall -Wextra -pedantic -O2 togli_commenti.c -o togli_commenti
*/

int main(int argc, char **argv)
{				
	if(argc != 3)
	{
		printf("uso: %s fileInput fileOutput\n", argv[0]);
		return -1;
	}
			
	makeOutput(argv[1], argv[2]);
			
	return 0;
}
L'automa è implementato tramite switch come spiegato da Claudio_F qui.
È ormai difficile incontrare un cretino che non sia intelligente e un intelligente che non sia un cretino. [...] Oh i bei cretini di una volta! Genuini, integrali. Come il pane di casa. Come l'olio e il vino dei contadini. (da "Nero su nero" di Leonardo Sciascia)
ixamit
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 499
Iscrizione: giovedì 14 novembre 2013, 10:16

Re: [C] Eliminare commenti da un file sorgente in C

Messaggio da ixamit »

ciao Vincenzo1968!
E' buggata, ma del resto come la mia e quella di ale4.
Sotto trovi gli estremi:

Codice: Seleziona tutto

#include <xxx/yyy.h>
void foo()
{
    int a=4/2;
}
Avatar utente
Vincenzo1968
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 450
Iscrizione: lunedì 14 gennaio 2013, 14:21
Desktop: Unity
Distribuzione: Ubuntu 18.04.3 LTS x86_64
Località: Villabate(PA)
Contatti:

Re: [C] Eliminare commenti da un file sorgente in C

Messaggio da Vincenzo1968 »

ixamit [url=http://forum.ubuntu-it.org/viewtopic.php?p=4853001#p4853001][img]http://forum.ubuntu-it.org/images/icons/icona-cita.gif[/img][/url] ha scritto:ciao Vincenzo1968!
E' buggata, ma del resto come la mia e quella di ale4.
Sotto trovi gli estremi:

Codice: Seleziona tutto

#include <xxx/yyy.h>
void foo()
{
    int a=4/2;
}
Ciao ixamit,

grazie per la segnalazione.

Così dovrebbe andare:

Codice: Seleziona tutto

#define _FILE_OFFSET_BITS 64

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BLOCK_SIZE 4096

typedef enum tagStates
{
	S0,
	S1,
	S2,
	S3,
	S4,
	S5,
	S6,
	S7,
	S8
} States;

int makeOutput(const char *szFileName, const char *szNewFileName);

int makeOutput(const char *szFileName, const char *szNewFileName)
{
	int retValue = 1;
	
	FILE *fp = NULL;
	FILE *fpNew = NULL;
	unsigned char *myBlock = NULL;
	unsigned char *myBlockNew = NULL;
	
	int blockLen = 0;
	int index1 = 0;	
	int index2 = 0;
	
	States state = S0;
	char c;
	
	myBlock = (unsigned char *)malloc(sizeof(unsigned char) * BLOCK_SIZE);
	if ( !myBlock )
	{
		printf("Memoria insufficiente.\n");
		retValue = 0;
		goto uscita;
	}	
	
	myBlockNew = (unsigned char *)malloc(sizeof(unsigned char) * BLOCK_SIZE);
	if ( !myBlockNew )
	{
		printf("Memoria insufficiente.\n");
		retValue = 0;
		goto uscita;
	}	
	
	fp = fopen(szFileName, "rb");
	if ( fp == NULL )
	{
		printf("Errore nell'apertura del file '%s'.\n", szFileName);
		retValue = 0;
		goto uscita;
	}
	
	fpNew = fopen(szNewFileName, "wb");
	if ( fpNew == NULL )
	{
		printf("Errore nella creazione del file '%s'.\n", szNewFileName);
		retValue = 0;
		goto uscita;
	}		
	
	while ( (blockLen = fread(myBlock, 1, BLOCK_SIZE, fp)) )
	{
		index1 = 0;
		
		while ( index1 < blockLen )
		{		
			c = myBlock[index1++];
		
			switch ( state )
			{
				case S0:
					if ( c == '/' )
					{
						state = S1;
					}
					else if ( c == '"' )
					{
						myBlockNew[index2++] = c;					
															
						state = S2;
					}
					else if ( c == '\'' )
					{
						myBlockNew[index2++] = c;					
															
						state = S7;
					}					
					else
					{
						myBlockNew[index2++] = c;										
					}				
					break;
				case S1:
					if ( c == '*' )
					{
						state = S3;
					}
					else if ( c == '/' )
					{
						state = S4;
					}					
					else
					{
						myBlockNew[index2++] = '/';
						
						if ( index2 >= BLOCK_SIZE )
						{
							fwrite(myBlockNew, 1, BLOCK_SIZE, fpNew);
							index2 = 0;
						}									
						
						myBlockNew[index2++] = c;
						
						state = S0;
					}
					break;
				case S2:
					myBlockNew[index2++] = c;					
															
					if ( c == '"' )
					{
						state = S0;
					}
					else if ( c == '\\' )
					{						
						state = S5;
					}
					break;
				case S3:
					if ( c == '*' )
					{					
						state = S6;
					}
					break;								
				case S4:				
					if ( c == '\r' || c == '\n' )
					{	
						myBlockNew[index2++] = c;
																										
						state = S0;
					}
					break;
				case S5:
					myBlockNew[index2++] = c;
											
					state = S2;
					break;
				case S6:
					if ( c == '/' )
					{					
						state = S0;
					}
					else
					{
						state = S3;
					}
					break;
				case S7:
					myBlockNew[index2++] = c;
					
					if ( c >= '\\' )
					{						
						state = S8;
					}
					else if ( c == '\'' )
					{
						state = S0;
					}				
					break;
				case S8:
					myBlockNew[index2++] = c;
					
					state = S7;
					break;																		
			} /* Fine switch */	
			
			if ( index2 >= BLOCK_SIZE )
			{
				fwrite(myBlockNew, 1, BLOCK_SIZE, fpNew);
				index2 = 0;
			}			
		}			
	}	
	
	if ( index2 > 0 )
		fwrite(myBlockNew, index2, 1, fpNew);	
	
uscita:
	if ( myBlock)
		free(myBlock);
	if (myBlockNew )
		free(myBlockNew);
	if ( fp )
		fclose(fp);
	if ( fpNew )
		fclose(fpNew);
	
	return retValue;
}

/*
gcc -Wall -Wextra -pedantic -O2 togli_commenti.c -o togli_commenti
*/

int main(int argc, char **argv)
{				
	if(argc != 3)
	{
		printf("uso: %s fileInput fileOutput\n", argv[0]);
		return -1;
	}
			
	makeOutput(argv[1], argv[2]);
			
	return 0;
}
È ormai difficile incontrare un cretino che non sia intelligente e un intelligente che non sia un cretino. [...] Oh i bei cretini di una volta! Genuini, integrali. Come il pane di casa. Come l'olio e il vino dei contadini. (da "Nero su nero" di Leonardo Sciascia)
Avatar utente
Claudio_F
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1463
Iscrizione: lunedì 28 maggio 2012, 18:49
Desktop: Mate/Gnome
Distribuzione: Ubu22.04

Re: [C] Eliminare commenti da un file sorgente in C

Messaggio da Claudio_F »

@Vincenzo mi sa che ho letto la prima versione, gli stati sono praticamente gli stessi a cui avevo pensato io ma c'è qualche errore di logica come il mancato ritorno allo stato 0 dopo aver rilevato il primo /.
Comunque mi sembra inutile fare un enum S0 S1 S2 ecc per indicare 0 1 2 ecc :p Mi sembra più utile/comprensibile qualcosa del genere:

Codice: Seleziona tutto

typedef enum tagStates
{
   Normal,      // codice normale
   InStr,       // all'interno di una stringa
   InChr,       // all'interno di un carattere
   EscStr,      // sequenza escape in stringa
   EscChr,      // sequenza escape in carattere
   Sdetect,     // rilevato possibile / inizio commento
   Mdetect,     // rilevato possibile * di fine commento
   BsDetect,    // rilevato \ finale in commento //
   ComSS,       // all'interno di commento //
   ComSM,       // all' interno di commento /* */
   Error        // errore fine riga in stringa o carattere
} States;
L'automa corretto di quelle poche cose che ho visto dovrebbe essere questo:

Codice: Seleziona tutto

switch ( state ){

    case Normal:
       if ( c == '/' )        state = Sdetect;
       else if ( c == '"' )  {myBlockNew[index2++] = c; state = InStr;}
       else if ( c == '\'' ) {myBlockNew[index2++] = c; state = InChr;}
       else                   myBlockNew[index2++] = c;
       break;


    case InStr:
       myBlockNew[index2++] = c;               
       if ( c == '\r' || c == '\n' )  state = Error;
       else if ( c == '"' )           state = Normal;
       else if ( c == '\\' )          state = EscStr;
       break;


    case EscStr:
       myBlockNew[index2++] = c;
       state = InStr;
       break;


    case InChr:
       myBlockNew[index2++] = c;
       if ( c == '\r' || c == '\n' )  state = Error;
       else if ( c == '\'' )          state = Normal;
       else if ( c == '\\' )          state = EscChr;
       break;


    case EscChr:
       myBlockNew[index2++] = c;
       if ( c == '\r' || c == '\n' )  state = Error;
       else                           state = InChr;
       break;


    case Sdetect:
       if ( c == '*' )        state = ComSM;
       else if ( c == '/' )   state = ComSS;
       else                  {myBlockNew[index2++] = '/';
                              myBlockNew[index2++] = c;
                              state = Normal;}
       break;


    case ComSS:
       if ( c == '\r' || c == '\n' ) {myBlockNew[index2++] = c;
                                      state = Normal;}
       else if ( c == '\\' )          state = BsDetect;
       break;


    case BsDetect:
       myBlockNew[index2++] = c;
       state = ComSS;
       break;


    case ComSM:
       if ( c == '*' )  state = Mdetect;
       break;                       


    case Mdetect:
       if ( c == '/' )  state = Normal;
       else             state = ComSM;
       break;


    case Error;
       break;

} /* Fine switch */
Immagine
EDIT: aggiunto possibilità di \ finale in stringhe e commenti per continuazione su riga successiva
Ultima modifica di Claudio_F il mercoledì 17 febbraio 2016, 18:10, modificato 2 volte in totale.
Avatar utente
Vincenzo1968
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 450
Iscrizione: lunedì 14 gennaio 2013, 14:21
Desktop: Unity
Distribuzione: Ubuntu 18.04.3 LTS x86_64
Località: Villabate(PA)
Contatti:

Re: [C] Eliminare commenti da un file sorgente in C

Messaggio da Vincenzo1968 »

Claudio_F [url=http://forum.ubuntu-it.org/viewtopic.php?p=4853037#p4853037][img]http://forum.ubuntu-it.org/images/icons/icona-cita.gif[/img][/url] ha scritto:@Vincenzo mi sa che ho letto la prima versione, gli stati sono praticamente gli stessi a cui avevo pensato io ma c'è qualche errore di logica come il mancato ritorno allo stato 0 dopo aver rilevato il primo /.
Si infatti. È per questo che l'output col sorgente postato da ixamit risulta errato(si mangia il "/": p. es. "4/2" nel sorgente, diventa "42" nel file di output). Ho corretto nella seconda versione.
Comunque mi sembra inutile fare un enum S0 S1 S2 ecc per indicare 0 1 2 ecc :p Mi sembra più utile/comprensibile qualcosa del genere:
Giustissimo. Usare nomi esplicativi rende il codice più leggibile. Mea culpa.
È ormai difficile incontrare un cretino che non sia intelligente e un intelligente che non sia un cretino. [...] Oh i bei cretini di una volta! Genuini, integrali. Come il pane di casa. Come l'olio e il vino dei contadini. (da "Nero su nero" di Leonardo Sciascia)
Scrivi risposta

Ritorna a “Programmazione”

Chi c’è in linea

Visualizzano questa sezione: 0 utenti iscritti e 21 ospiti