На Brainfuck в C конвертер


Эта программа преобразует исходный код на Brainfuck-C и компилирует его с помощью GCC. Он работает очень хорошо (это был мой первый раз, когда я играл затерянного Королевства), однако, код довольно долго, потому что некоторые детали повторяются.

Есть ли способ уменьшить объем кода? Насчет "оптимизации" метод? Может этот простой оптимизации можно усовершенствовать?

PS: этот код для Linux, но может быть изменен для Windows.

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

int main(int argv, char* argc[]){
    //help message
    if(argv==1){
        printf("\n");
        printf("How to use : %s filename [-o output|-c|-d|-r]\n",argc[0]);
        printf("-o output : Set output file name\n-c : Do not compile\n-d : Do not delete C source file\n");
        printf("INFO : You SHOULD type 'export MALLOC_CHECK_=0' manually to remove warning.\n");
        printf("\n");
        return 0;
    }
    printf("INFO : You may type 'export MALLOC_CHECK_=0' manually to remove warning.\n");
    int i;
    bool doCompile = true;
    bool deleteSource = true;
    char* fileName = argc[1];
    char* outFileName;
    outFileName = (char*)malloc(1024);
    strncpy(outFileName,fileName,1000);
    strcat(outFileName,".o");
    bool isSetOut = false;
    //set flags 
    for(i=2;i<argv;i++){
        if(isSetOut){
            isSetOut = false;
            outFileName = argc[i];
        }
        else if(strcmp(argc[i],"-c")==0){
            doCompile = false;
        }
        else if(strcmp(argc[i],"-d")==0){
            deleteSource = false;
        }
        else if(strcmp(argc[i],"-o")==0){
            isSetOut = true;
        }
    }
    char outFileC[1024];
    strncpy(outFileC,outFileName,1000);
    strcat(outFileC,".c");

    //bf file
    FILE* bfFile;
    bfFile = fopen(fileName,"r");
    if(bfFile==NULL){
        printf("ERROR : FILE %s DOES NOT EXIST\n",fileName);
        return 2;
    }
    char c;

    //c source code
    FILE* cFile;
    cFile = fopen(outFileC,"w");
    int add = 0;
    char prevC = '\0';
    fputs("#include<stdio.h>\n#include<stdlib.h>\n",cFile);
    fputs("int main(){",cFile);
    fputs("unsigned char* _=(unsigned char*)malloc(32*1024);/*32kB*/if(_==0){printf(\"MEMORY ERROR!\\n\");return 1;}",cFile);
    //write codes   
    do{
        c = fgetc(bfFile);
        if(c!=EOF){
            bool isPrint = false;
            switch(c){
                case '>':
                case '<':
                    if((prevC=='+'||prevC=='-')&&add){//process something like +++- = ++
                        if(add==1||add==-1){
                            if(add==1) fputs("++*_",cFile);
                            else fputs("--*_",cFile);
                        }
                        else fprintf(cFile,"(*_)%c=%d",add>0?'+':'-',add>0?add:-add);
                        fputs(";",cFile);
                        add=0;
                    }
                    if(c=='>') add++;
                    else add--;
                    break;
                case '+':
                case '-':
                    if((prevC=='>'||prevC=='<')&&add){//process something like >>>< = >>
                        if(add==1||add==-1){
                            if(add==1) fputs("++_",cFile);
                            else fputs("--_",cFile);
                        }
                        else fprintf(cFile,"_%c=%d",add>0?'+':'-',add>0?add:-add);
                        fputs(";",cFile);
                        add=0;
                    }
                    if(c=='+') add++;
                    else add--;
                    break;
                case '.':
                case ',':
                case '[':
                case ']':
                    if(add){
                        if(prevC=='>'||prevC=='<'){//process something like >>>< = >>
                            if(add==1||add==-1){
                                if(c=='.'){
                                    isPrint = true;
                                    if(add==1) fputs("putchar(*(++_))",cFile);
                                    else fputs("putchar(*(--_))",cFile);
                                }else{
                                    if(add==1) fputs("++_",cFile);
                                    else fputs("--_",cFile);
                                }
                            }
                            else if(c=='.'){
                                isPrint = true;
                                fprintf(cFile,"putchar(*(_%c=%d))",add>0?'+':'-',add>0?add:-add);
                            }else fprintf(cFile,"_%c=%d",add>0?'+':'-',add>0?add:-add);
                            fputs(";",cFile);
                            add=0;
                        }else if(prevC=='+'||prevC=='-'){//process something like +++- = ++
                            if(add==1||add==-1){
                                if(c=='.'){
                                    isPrint = true;
                                    if(add==1) fputs("putchar(++*_)",cFile);
                                    else fputs("putchar(--*_)",cFile);
                                }else{
                                    if(add==1) fputs("++*_",cFile);
                                    else fputs("--*_",cFile);
                                }
                            }
                            else if(c=='.'){
                                isPrint = true;
                                fprintf(cFile,"putchar((*_)%c=%d)",add>0?'+':'-',add>0?add:-add);
                            }else fprintf(cFile,"(*_)%c=%d",add>0?'+':'-',add>0?add:-add);
                            fputs(";",cFile);
                            add=0;
                        }
                    }
                    switch(c){
                        case '.':
                            if(!isPrint) fputs("putchar(*_);",cFile);
                            break;
                        case ',':
                            fputs("*_=getchar();",cFile);
                            break;
                        case '[':
                            fputs("while(*_){",cFile);
                            break;
                        case ']':
                            fputs("}",cFile);
                            break;
                    }
                    break;
            }
        }
        if(c=='>'||c=='<'||c=='+'||c=='-'||c=='.'||c==','||c=='['||c==']') prevC = c;
    }while(c!=EOF);
    fputs("free(_);return 0;}",cFile);
    fclose(bfFile);
    fclose(cFile);
    if(!doCompile){
        printf("Output C code : %s\n",outFileC);
        return 0;
    }
    printf("Compile with GCC...\n");
    char op[2048] = "gcc ";
    strcat(op,outFileC);
    strcat(op," -o ");
    strcat(op,outFileName);
    system(op);
    if(deleteSource){
        strcpy(op,"rm ");
        strcat(op,outFileC);
        system(op);
    }
    printf("Done.\nOutput file name : %s\n",outFileName);
    return 0;
}


839
14
задан 17 мая 2011 в 10:05 Источник Поделиться
Комментарии
3 ответа


  1. Не складывай все в гигантскую функцию main, что делает его трудно следовать

  2. Сообщение об ошибке печати, такие как использование информации в stderr

  3. У вас есть АГДС (аргумент графа) и argv (аргумент вектора) назад

  4. Вы не бесплатно все, что вы Танос

  5. Нет смысла в mallocing, потому что вы можете создавать свои массивы на стеке

  6. А потом прохождения значительно меньшее значение, как ваш размер, чтобы функції strncpy, strncat использовать для конкатенации.

  7. Повторяющиеся константы, такие как размер строки, которые вы используете лучше всего определяет

  8. Поскольку вы, кажется, используете новую версию C, не сплит определения и задания на отдельные линии unneccesairly

  9. Я предпочитаю класть логика в другие блоки, а затем в зависимости от возврата пропуская все остальное.

  10. А потом звонит РМ, использование стандартной библиотеки функция "отвязать" для удаления файлов

  11. Не генерировать код, используя ++/-- это не поможет конечная скорость и делает ваш код более сложным

  12. Не пытайтесь вместо сложение отрицательных чисел, компилятор достаточно умен, чтобы справиться, что убавить.

  13. Почему не точка с запятой внутри функции printf?

  14. Имя добавить не очень понятно. Мне потребовалось некоторое время, чтобы выяснить, что он делал

  15. В целом вы тратите много усилий, пытаясь создать более компактный код C. Но компилятор C будет умнее в этом, что вы находитесь, так что не попробовать.

Убрав эти вопросы я вижу проблематичным повторение логики. Первая вещь заключается в том, что все не БФ персонажи вызывают осложнений. Мы напишем функцию, которая вызывает то fgetc, но отфильтровывает всех персонажей, мы хотим игнорировать.

Далее, а затем пытаются ответить на один символ за раз, есть петли, которые едят герои.

Вот результат:

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

#define STRING_SIZE 1024

typedef struct CommandOptions
{
bool doCompile;
bool deleteSource;
char * fileName;
char outFileName[STRING_SIZE];
char outFileC[STRING_SIZE];
}CommandOptions;

bool parse_command_line(CommandOptions * options, int argc, char * argv[])
{
//help message
if(argc==1){
fprintf(stderr, "\n");
fprintf(stderr, "How to use : %s filename [-o output|-c|-d|-r]\n",argv[0]);
fprintf(stderr, "-o output : Set output file name\n-c : Do not compile\n-d : Do not delete C source file\n");
fprintf(stderr, "INFO : You SHOULD type 'export MALLOC_CHECK_=0' manually to remove warning.\n");
fprintf(stderr, "\n");
return false;
}

// set the default options
options->doCompile = true;
options->deleteSource = true;
options->fileName = argv[1];

strncpy(options->outFileName, options->fileName, STRING_SIZE);
strncat(options->outFileName, ".o", STRING_SIZE);

// parse the remaining options
int i;
bool isSetOut = false;

for(i = 0; i < argc; i++)
{
if(isSetOut){
isSetOut = false;
strncpy(options->outFileName, argv[i], STRING_SIZE);
}
else if(strcmp(argv[i],"-c")==0){
options->doCompile = false;
}
else if(strcmp(argv[i],"-d")==0){
options->deleteSource = false;
}
else if(strcmp(argv[i],"-o")==0){
isSetOut = true;
}
}

strncpy(options->outFileC,options->outFileName,STRING_SIZE);
strncat(options->outFileC,".c", STRING_SIZE);

// don't delete the source if we won't compile it
if(!options->doCompile)
{
options->deleteSource = false;
}

return true;

}

void write_header(FILE * cFile)
{
fputs("#include<stdio.h>\n", cFile);
fputs("#include<stdlib.h>\n",cFile);
fputs("int main(){\n",cFile);
fputs("unsigned char* _=(unsigned char*)malloc(32*1024);/*32kB*/if(_==0){printf(\"MEMORY ERROR!\\n\");return 1;}\n",cFile);
}

void write_footer(FILE * cFile)
{
fputs("free(_);\nreturn 0;\n}\n",cFile);
}

int bf_fgetc(FILE * bfFile)
{
int c;
do
{
c = fgetc(bfFile);
}while(c != EOF && c != '[' && c != ']' && c != '<' && c != '>' && c != '.'
&& c != ',' && c != '+' && c != '-');
return c;
}

void compile_to_c(FILE * bfFile, FILE * cFile)
{
write_header(cFile);
int add = 0;
char prevC = '\0';
//write codes
char c = bf_fgetc(bfFile);
do{
int movement_counter = 0;
while( c == '>' || c == '<')
{
movement_counter += c == '>' ? 1 : -1;
c = bf_fgetc(bfFile);
}
if(movement_counter)
{
fprintf(cFile,"_ += %d;", movement_counter);
}

int value_counter = 0;
while( c == '+' || c == '-')
{
value_counter += c == '+' ? 1 : -1;
c = bf_fgetc(bfFile);
}
if(value_counter)
{
fprintf(cFile,"*_ += %d;",value_counter);
}

if(c == '.')
{
fprintf(cFile, "putchar(*_);\n");
c = bf_fgetc(bfFile);
}
if(c == ',')
{
fprintf(cFile, "*_ = getchar();\n");
c = bf_fgetc(bfFile);
}
if(c == '[')
{
fprintf(cFile, "while(*_) {\n");
c = bf_fgetc(bfFile);
}
if(c == ']')
{
fprintf(cFile, "}\n");
c = bf_fgetc(bfFile);
}
}while(c!=EOF);
write_footer(cFile);
}

void compileCode(CommandOptions * options)
{
printf("Compile with GCC...\n");
char op[2048] = "gcc ";
strncat(op,options->outFileC, 2048);
strncat(op," -o ", 2048);
strncat(op,options->outFileName, 2048);
system(op);
}

int main(int argc, char* argv[]){
CommandOptions options;

if( !parse_command_line(&options, argc, argv) )
{
return 1;
}

printf("INFO : You may type 'export MALLOC_CHECK_=0' manually to remove warning.\n");

//bf file
FILE* bfFile = fopen(options.fileName,"r");
if(bfFile==NULL){
fprintf(stderr, "ERROR : FILE %s DOES NOT EXIST\n",options.fileName);
return 2;
}

//c source code
FILE* cFile = fopen(options.outFileC, "w");
if(!cFile)
{
fclose(bfFile);
fprintf(stderr, "ERROR: COULD NOT OPEN %s FILE FOR WRITING" , options.outFileC);
return 3;
}

compile_to_c(bfFile, cFile);

fclose(bfFile);
fclose(cFile);

if(options.doCompile){
compileCode(&options);
}else{
printf("Output C code : %s\n", options.outFileC);
}

if( options.deleteSource )
{
unlink(options.outFileC);
}

printf("Done.\nOutput file name : %s\n",options.outFileName);
return 0;
}

Есть еще некоторые дублирования в функции compile_to_c, что мне не нравится. Сходство между <> и +- может легко быть легко использованы в функции. Сложнее будет избавиться от повторяющихся bf_fgetc звонки.

17
ответ дан 18 мая 2011 в 02:05 Источник Поделиться

У вас есть два управления памятью ошибки.

Память возвращается из функции malloc() , в общем, не инициализируется нулями. Хорошая операционная система будет ноль всех страниц памяти, которые приводятся в вашей программе (для предотвращения утечки информации из других программ), и программы первой функции malloc() , вероятно, получить девственницы памяти. Однако, все это не гарантируется в POSIX. Я предлагаю вызов метода calloc() вместо этого.

Указатель, что вы бесплатно() не обязательно имеют то же значение, которое вы получили от malloc()в. Указатель может принимать любое значение, как она движется среди клеток. Если указатель мыши не окажутся в ячейке 0, когда программа запускается из инструкции для выполнения, то вы в конечном итоге освобождая произвольный указатель, а жаль, когда ты так близко для успешного окончания!

Возможные средства правовой защиты являются:


  • Сохраните копию значение, возвращаемое из функции malloc() , так что вы можете бесплатно() это.

  • Не пытайтесь звонить бесплатно(); просто пусть ОС позаботиться об очистке.

  • Поскольку вы только делаете фиксированный размер выделения, просто использовать массив: неподписанные символ памяти[32 * 1024] ={ 0 }, *_ = память;

5
ответ дан 15 января 2014 в 10:01 Источник Поделиться

Не бросайте Танос. Это не нужно в C, и может скрываться ошибка, если вы не имеете действительный прототип в область (т. е. вы не включили stdlib.з)

3
ответ дан 20 августа 2011 в 12:08 Источник Поделиться