Calcolabilità, programma C che prende in input se stesso
Abbiamo visto a lezione che non può esistere una macchina di Turing che rifiuta se stessa (concetto che trovo filosoficamente intrigante), di qui però la curiosità:
come scrivo un programma C che ritorni "true" (0) $<=>$ se riceve in input esattamente il codice sorgente che lo ha generato e "false" (1) altrimenti? (auto-accettazione, teoricamente possibile.. come?)
Così funzionerebbe, però è troppo facile, e noi siamo masochisti, lo scopo è realizzare suddetto programma C senza utilizzare librerie esterne (nemmeno quelle di sistema come stdio.h), deve stare tutto nel "main.c" (la stringa che contiene il sorgente del programma è passata da argv)
Qualcuno ha qualche idea? Ci ho pensato un pochino e non è così banale.
Una prima idea sarebbe che il programma abbia una "C-stringa" che contenga il suo stesso codice, ma questo diventerebbe ricorsivo e quindi una stringa infinita, allora ho pensato che si può alterare leggermente il programma per vedere se una stringa in input è la composizione doppia (non la definisco, capitemi XD) di una stringa che ho in memoria, a questo punto sembra funzionare (tranne forse i caratteri di escape che sono ancora da sistemare)
come scrivo un programma C che ritorni "true" (0) $<=>$ se riceve in input esattamente il codice sorgente che lo ha generato e "false" (1) altrimenti? (auto-accettazione, teoricamente possibile.. come?)
int main(int argc, char** argv ){ if(riconosciInput(argc,argv[1]) == 0) //con == 1 avrei un paradosso return 0; else return 1; }
Così funzionerebbe, però è troppo facile, e noi siamo masochisti, lo scopo è realizzare suddetto programma C senza utilizzare librerie esterne (nemmeno quelle di sistema come stdio.h), deve stare tutto nel "main.c" (la stringa che contiene il sorgente del programma è passata da argv)
Qualcuno ha qualche idea? Ci ho pensato un pochino e non è così banale.
Una prima idea sarebbe che il programma abbia una "C-stringa" che contenga il suo stesso codice, ma questo diventerebbe ricorsivo e quindi una stringa infinita, allora ho pensato che si può alterare leggermente il programma per vedere se una stringa in input è la composizione doppia (non la definisco, capitemi XD) di una stringa che ho in memoria, a questo punto sembra funzionare (tranne forse i caratteri di escape che sono ancora da sistemare)
Risposte
Ma quella funzione che hai scritto nel codice cosa dovrebbe fare? Leggere il codice da file e confrontarlo con la stringa?
L'unico input ammesso è una stringa (stile C) che viene passata al main (nessun file di "lookup" quindi, sennò è banalissimo). Il main deve ritornare 0 $<=>$ la stringa è il codice sorgente del main.c
Una possibile implementazione di
Che però non va bene perchè anche la funzione "riconosciInput" deve stare nel main.
Qui lo scopo è trovare un programma che riconosce se stesso, quindi un file "main.c" che se compilato diventa un eseguibile che ritorna 0 $<=>$ riceve come input il codice sorgente di "main.c" (senza usare headers di nessun tipo, e senza quindi la possibilità di andare a leggere un file)
Una possibile implementazione di
int riconosciInput(int argc, char * argv){ char my_string[] = "int main(int argc, char** argv ){\n" " if(riconosciInput(argc,argv[1]) == 0) ////con == 1 avrei un paradosso\n" //escape di "/" " return 0;\n" " else\n" " return 1;\n" "}\n"; return strcmp(argv,my_string)==0?0:1; }
Che però non va bene perchè anche la funzione "riconosciInput" deve stare nel main.
Qui lo scopo è trovare un programma che riconosce se stesso, quindi un file "main.c" che se compilato diventa un eseguibile che ritorna 0 $<=>$ riceve come input il codice sorgente di "main.c" (senza usare headers di nessun tipo, e senza quindi la possibilità di andare a leggere un file)
Un'idea potrebbe essere qualcosa come il seguente. Spero sia chiaro, non l'ho testato ma è l'idea che conta (in pratica sarebbe più facile usare uno script esterno per scriverlo per bene). Quella alla fine è un'unica riga..
extern char *source; int main(int argc, char *argv[]) { int i = 0; while (source[i] && argv[1][i]) { if (source[i] != argv[1][i]) { return 0; } } if (argv[1][i++] || argv[1][i++] != '\"') { return 0; } for (int j = 0; source[j] && argv[1][i]; ++i, ++j) { if (argv[1][i] == '\\') { if (argv[1][++i] == '\"' && source[j] != '\"' || argv[1][i] != 'n' && source[j] != '\n' || argv[1][i] != '\\' && source [j] != '\\') { return 0; } } if (source[j] != argv[1][i]) { return 0; } } if (argv[1][i++] != '\"' || argv[1][i++] != ';' || !argv[1][i]) { return 0; } return 1; } char *source = "extern char *source;\nint main(int argc, char *argv[]) {\n int i = 0;\n while (source[i] && argv[1][i]) {\n if (source[i] != argv[1][i]) { return 0; }\n }\n if (argv[1][i++] || argv[1][i++] != '\\\"') { return 0; }\n for (int j = 0; source[j] && argv[1][i]; ++i, ++j) {\n if (argv[1][i] == '\\\\') {\n if (argv[1][++i] == '\\\"' && source[j] != '\\\"'\n || argv[1][i] != 'n' && source[j] != '\\n'\n || argv[1][i] != '\\\\' && source [j] != '\\\\') {\n return 0;\n }\n }\n if (source[j] != argv[1][i]) { return 0; }\n }\n if (argv[1][i++] != '\\\"' || argv[1][i++] != ';' || !argv[1][i]) { return 0; }\n return 1;\n}\nchar *source = ";
"apatriarca":
Un'idea potrebbe essere qualcosa come il seguente. Spero sia chiaro, non l'ho testato ma è l'idea che conta (in pratica sarebbe più facile usare uno script esterno per scriverlo per bene). Quella alla fine è un'unica riga..
extern char *source; int main(int argc, char *argv[]) { int i = 0; while (source[i] && argv[1][i]) { if (source[i] != argv[1][i]) { return 0; } } if (argv[1][i++] || argv[1][i++] != '\"') { return 0; } for (int j = 0; source[j] && argv[1][i]; ++i, ++j) { if (argv[1][i] == '\\') { if (argv[1][++i] == '\"' && source[j] != '\"' || argv[1][i] != 'n' && source[j] != '\n' || argv[1][i] != '\\' && source [j] != '\\') { return 0; } } if (source[j] != argv[1][i]) { return 0; } } if (argv[1][i++] != '\"' || argv[1][i++] != ';' || !argv[1][i]) { return 0; } return 1; } char *source = "extern char *source;\nint main(int argc, char *argv[]) {\n int i = 0;\n while (source[i] && argv[1][i]) {\n if (source[i] != argv[1][i]) { return 0; }\n }\n if (argv[1][i++] || argv[1][i++] != '\\\"') { return 0; }\n for (int j = 0; source[j] && argv[1][i]; ++i, ++j) {\n if (argv[1][i] == '\\\\') {\n if (argv[1][++i] == '\\\"' && source[j] != '\\\"'\n || argv[1][i] != 'n' && source[j] != '\\n'\n || argv[1][i] != '\\\\' && source [j] != '\\\\') {\n return 0;\n }\n }\n if (source[j] != argv[1][i]) { return 0; }\n }\n if (argv[1][i++] != '\\\"' || argv[1][i++] != ';' || !argv[1][i]) { return 0; }\n return 1;\n}\nchar *source = ";
non funziona così,
anche
char *source = "extern char *sou ...
fa parte del main.
L'idea è quella che citavo appunto nel primo post, se includessi a questo punto anche "la stringa"
diventerebbe una ricorsione infinita.
(però è un primo passo per risolvere i problemi di escape! XD GRANDE!)
EDIT:
FUNZIONA IN TEORIA

Non c'è ricorsione infinita. Se guardi bene la stringa non contiene tutto il codice, ma solo fino all'inizio della stringa. A questo punto il codice verifica che nella stringa passata ci sia un " e poi gestisce i carattere di escape necessari per poter confrontare effettivamente sorgente e stringa. Infine si aspetta la presenza di un " e di un ; per terminare il codice.
Si! ho visto
niente ricorsione infinita GRANDE:). Il pezzo mancante credo siano ancora i caratteri di escape. (ho editato, ma non in tempo sei stato troppo veloce)
visto che la stringa contiene cose come "////" che il compilatore traduce in automatico in '//', serve anche una funzione che fa l'anti-escape e trasforma "//" la in '////' (o se vogliamo "////////"). Questa funzione può essere tranquillamente dichiarata e definita nel main.c per fortuna
altrimenti erano guai
Quindi una volta prende la stringa così com'è, la seconda fa l'anti-escape per trasformarla in una stringa che se compilata diventa la prima.. (che robe contorte)
però quindi la teoria si può tradurre in pratica. Il programma C che riconosce se stesso $\exists$
Grazie:)

visto che la stringa contiene cose come "////" che il compilatore traduce in automatico in '//', serve anche una funzione che fa l'anti-escape e trasforma "//" la in '////' (o se vogliamo "////////"). Questa funzione può essere tranquillamente dichiarata e definita nel main.c per fortuna

Quindi una volta prende la stringa così com'è, la seconda fa l'anti-escape per trasformarla in una stringa che se compilata diventa la prima.. (che robe contorte)
però quindi la teoria si può tradurre in pratica. Il programma C che riconosce se stesso $\exists$
Grazie:)