Buat preprocessor C

18

Tujuannya adalah untuk membuat preprosesor untuk bahasa C, sekecil mungkin dalam hal ukuran kode sumber dalam byte , dalam bahasa pilihan Anda. Inputnya akan berupa file sumber C, dan outputnya akan menjadi kode sumber yang sudah diproses.

Item-item yang harus dapat diproses adalah: Penghapusan komentar (baris / blok), # sertakan arahan (dengan membuka file di jalur relatif dan mengganti teks pada titik yang diperlukan), #define, #undef, #if, #elif, #else, #endif, #ifdef, #ifndef, dan defined (). Arahan preprocessor C lainnya seperti #pragmas atau #errors dapat diabaikan.

Tidak perlu menghitung ekspresi aritmatika atau operator pembanding dalam arahan #jika kita mengasumsikan ekspresi akan bernilai true asalkan berisi bilangan bulat selain nol (penggunaan utamanya adalah untuk direktif yang didefinisikan ()). Contoh kemungkinan input dan output yang diikuti (kemungkinan spasi putih tambahan dalam file output dipangkas untuk penampilan yang lebih baik, tidak perlu kode Anda untuk melakukannya). Suatu program yang dapat memproses contoh-contoh berikut dengan benar akan dianggap memadai.

----Input file: foo.c (main file being preprocessed)

#include "bar.h" // Line may or may not exist

#ifdef NEEDS_BAZZER
#include "baz.h"
#endif // NEEDS_BAZZER

#ifdef _BAZ_H_

int main(int argc, char ** argv)
{
    /*  Main function.
        In case that bar.h defined NEEDS_BAZ as true,
        we call baz.h's macro BAZZER with the length of the
        program's argument list. */
    return BAZZER(argc);
}

#elif defined(_BAR_H_)

// In case that bar.h was included but didn't define NEEDS_BAZ.
#undef _BAR_H_
#define NEEDS_BARRER
#include "bar.h"

int main(int argc, char ** argv)
{
    return BARRER(argc);
}

#else

// In case that bar.h wasn't included at all.
int main()
{return 0;}

#endif // _BAZ_H_

----Input file bar.h (Included header)

#ifndef _BAR_H_
#define _BAR_H_

#ifdef NEEDS_BARRER

int bar(int * i)
{
    *i += 4 + *i;
    return *i;
}

#define BARRER(i) (bar(&i), i*=2, bar(&i))

#else
#define NEEDS_BAZZER // Line may or may not exist
#endif // NEEDS_BARRER

#endif // _BAR_H_

----Input file baz.h (Included header)

#ifndef _BAZ_H_
#define _BAZ_H_

int baz(int * i)
{
    *i = 4 * (*i + 2);
    return *i;
}

#define BAZZER(i) (baz(&i), i+=2, baz(&i))

#endif // _BAZ_H_

----Output file foopp.c (no edits)

int baz(int * i)
{
    *i = 4 * (*i + 2);
    return *i;
}

int main(int argc, char ** argv)
{
    return (baz(&argc), argc+=2, baz(&argc));
}

----Output file foopp2.c (with foo.c's first line removed)

int main()
{return 0;}

----Output file foopp3.c (with bar.h's line "#define NEEDS_BAZZER" removed)

int bar(int * i)
{
    *i += 4 + *i;
    return *i;
}

int main(int argc, char ** argv)
{
    return (bar(&argc), argc*=2, bar(&argc));
}
Thanasis Papoutsidakis
sumber
Bisakah Anda memberikan sampel input / output?
Florent
Berikan kami kode uji. Hampir mustahil tanpa contoh.
Ismael Miguel
Uh yakin, aku akan. Bersabarlah sedikit karena saya tidak bisa sangat cepat karena kendala waktu dan beban kerja.
Thanasis Papoutsidakis
1
Berapa banyak yang #ifperlu didukung? yaitu apakah preprocessor perlu mendukung ekspresi dengan aritmatika, operasi bitwise, dll?
Hasturkun
ok, contoh input / output dan penjelasan lebih lanjut ditambahkan
Thanasis Papoutsidakis

Jawaban:

8

Flex, 1170 + 4 = 1174

1170 karakter dalam kode fleksibel + 4 karakter untuk bendera kompilasi. Untuk menghasilkan yang dapat dieksekusi, jalankan flex pre.l ; gcc lex.yy.c -lfl. Entri bocor memori seperti saringan dan tidak menutup file yang disertakan. Tetapi jika tidak, itu harus sepenuhnya berfungsi sesuai spesifikasi.

%{
#define M malloc
#define X yytext
#define A a=X
#define B(x) BEGIN x;
#define Y YY_CURRENT_BUFFER
*a,*b,**v,**V,**t,**T,i,s=1,o;
g(){t=M(++s);T=M(s);for(i=1;i<s-1;i++)t[i]=v[i],T[i]=V[i];free(v);free(V);v=t;V=T;}
f(){for(i=1;i<s;i++)if(!strcmp(v[i],a))return i;return 0;}
d(y){X[yyleng-y]=0;}
%}
%x D F I
N .*\n
%%
"//".*
"/*"([^\*]|\*[^\/])*"*/"
\"(\\.|[^\\"])*\" ECHO;
^"#include "\"[^\"]*\" d(1),yypush_buffer_state(yy_create_buffer(fopen(X+10,"r"),YY_BUF_SIZE));
^"#define "[^ ]* {B(D)strcpy(a=M(yyleng),X+8);}
<D>" "?{N} {b=M(yyleng);d(1);f(strcpy(b,X+(X[0]==32)))?free(V[i]),V[i]=b:g(),v[s-1]=a,V[s-1]=b;B(0)}
^"#undef "{N} d(1),v[f(A+7)][0]=0;
^"#if defined(".*")\n" h(2,12);
^"#ifdef "{N} h(1,7);
^"#if "{N} {d(1);if(!atoi(X+4))B(F)}
^"#ifndef "{N} {d(1);if(f(A+8))B(F)}
<F>^"#if"{N} o++;
<F>^"#endif"{N} if(!o--)B(++o)
<F>^"#else"{N} if(!o)B(0)
<F>^"#elif defined(".*")\n" if(!o){d(2);if(f(A+14))B(0)}
<F>^"#elif "{N} if(!o){d(1);if(atoi(X+6))B(0)}
<F>{N}
^"#endif"{N}
^"#el"("se"|"if"){N} B(I)
<I>^"#endif"{N} B(0)
<I>{N}
[a-zA-Z_][a-zA-Z_0-9]* printf(f(A)?V[i]:a);
<<EOF>> {a=Y;yypop_buffer_state();if(!Y)exit(0);fclose(a);}
%%
h(x,y){d(x);if(!f(A+y))B(F)}

Beberapa penjelasan:

  • adan btemps untuk menahan string dari input. ajuga digunakan sebagai parameter untuk berfungsi f.
  • vmemegang nama-nama makro dan Vmemegang 'Nilai-nilai makro
  • tdan Tmerupakan pemegang sementara ketika kita tumbuh vdanV
  • i adalah 'i'ncrementer untuk loop
  • s adalah 's'ize dari array makro
  • oadalah hitungan dari 'o'pen ifs di dalam kondisi palsu
  • g() g'rows array makro
  • f()'menemukan makro dengan nilai yang sama vsebagaia
  • d(y)'memilih ykarakter terakhir dari input saat ini
  • negara Dadalah di dalam 'D'efine
  • negara Fadalah untuk mengabaikan persyaratan F'alse
  • negara Iadalah untuk 'Saya mengingat else/ elifsetelah kondisi yang benar ditemukan.

EDIT1: membersihkan banyak kebocoran memori dan menerapkan penutupan file

EDIT2: kode yang dimodifikasi untuk menangani makro bersarang lebih benar

EDIT3: jumlah golf yang gila

EDIT4: lebih banyak bermain golf

EDIT5: lebih banyak bermain golf; Saya juga memperhatikan bahwa panggilan saya ke fclose () menyebabkan masalah pada beberapa komputer ... melihat hal ini.

Josh
sumber
Ini berfungsi sangat baik sejauh ini pada sebagian besar kasus ... untuk beberapa alasan itu melempar kesalahan segmentasi ketika saya #includebarang, tapi saya kira ini terkait dengan bug di edit # 5. Juga tidak menggantikan makro, meskipun berhasil memproses blok # jika - kecuali saya melakukan sesuatu yang salah ... tetapi secara umum itu terlihat sangat baik, dan itu memberikan gambaran kasar tentang apa yang dapat dilakukan oleh seorang lexer, karena Saya bisa memahaminya bahkan dalam bentuk golf. Cobalah untuk melihat apakah bug dapat diperbaiki, jika tidak ok, karena kode menjelaskan dengan baik, mungkin ini akan dipilih karena tidak ada entri lain.
Thanasis Papoutsidakis