C önişlemcisi oluşturma


18

Amaç, tercih ettiğiniz dilde bayt cinsinden kaynak kodu boyutu açısından C dili için olabildiğince küçük bir ön işlemci oluşturmaktır . Girdi bir C kaynak dosyası ve çıktısı önceden işlenmiş kaynak kodu olacaktır.

İşleyebilmesi gereken öğeler: Yorum kaldırma (satır / blok), #include yönergeleri (dosyaları göreli yollarda açıp gereken noktadaki metni değiştirerek), #define, #undef, #if, #elif, #else, #endif, #ifdef, #ifndef ve tanımlanmış (). #Pragmas veya #errors gibi diğer C önişlemci yönergeleri yok sayılabilir.

#İf yönergelerinde aritmetik ifadelerin veya karşılaştırma işleçlerinin hesaplanmasına gerek yoktur, ifadenin sıfır dışında bir tamsayı içerdiği sürece doğru olarak değerlendirileceğini varsayarız (ana kullanımı tanımlanan () yönergesi için olacaktır). Olası girdi ve çıktı takibi örnekleri (çıktı dosyalarındaki olası ekstra boşluklar daha iyi görünmesi için kesilmiştir, kodunuzun buna gerek yoktur). Aşağıdaki örnekleri düzgün bir şekilde işleyebilen bir program yeterli kabul edilecektir.

----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));
}

Giriş / çıkış örnekleri sağlayabilir misiniz?
Florent

Bize bir test kodu verin. Örnekler olmadan neredeyse imkansız.
Ismael Miguel

Ah, eminim. Zaman ve iş yükü kısıtlamaları nedeniyle çok hızlı olamadığım için biraz sabırlı ol.
Thanasis Papoutsidakis

1
Ne kadar #ifdesteklenmesi gerekiyor? yani önişlemcinin aritmetik, bitsel işlemler, vb. içeren ifadeleri desteklemesi gerekiyor mu?
Hasturkun

tamam, örnek girdi / çıktı ve ek açıklamalar eklendi
Thanasis Papoutsidakis

Yanıtlar:


8

Esnek, 1170 + 4 = 1174

Esnek kodda 1170 karakter + bir derleme bayrağı için 4 karakter. Yürütülebilir bir dosya oluşturmak için çalıştırın flex pre.l ; gcc lex.yy.c -lfl. Giriş, bir elek gibi bellek sızdırıyor ve dahil edilen dosyaları kapatmıyor. Ancak aksi halde, spesifikasyona göre tamamen işlevsel olmalıdır.

%{
#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)}

Bazı açıklamalar:

  • ave bdizeleri girişten tutmak için temp'lerdir. aişlevi için parametre olarak da kullanılır f.
  • vmakroların isimlerini ve makroların V'V' değerlerini tutar
  • tve Tbüyüdüğümüzde vveV
  • i döngüler için bir 'i'ncrementer
  • s makro dizisinin 'boyutu'
  • oifyanlış koşullu 'açıklıkların sayısı'
  • g() 'makro dizileri'
  • f()'aynı değere sahip bir makro f'inds volaraka
  • d(y)' ygeçerli girişin son karakterlerini döndürür
  • devlet Dbir 'D'efine için
  • durumu Fbir 'F' alse koşulunu yok saymak içindir
  • devlet I'Ignoring else/ elifgerçek bir koşul bulundu sonra.

EDIT1: bellek sızıntılarının çoğunu temizledi ve dosya kapatmayı uyguladı

EDIT2: iç içe makroları daha doğru işlemek için değiştirilmiş kod

EDIT3: çılgın golf miktarı

EDIT4: daha fazla golf

EDIT5: daha fazla golf; Ayrıca fclose () çağrım bazı bilgisayarlarda sorunlara neden olduğunu fark ettim ... buna bakarak.


Şimdiye kadar çoğu durumda çok iyi çalışıyor ... bazı nedenlerden dolayı ben bir segmentasyon hatası atar #include, ama sanırım bu düzenleme # 5 hata ile ilgili. Ayrıca, #if bloklarını başarıyla işlese bile makroların yerini almaz - yanlış bir şey yapmadıkça ... ancak genel olarak çok iyi görünüyor ve bir lexerin neler yapabileceği hakkında kabaca bir fikir veriyor, çünkü Golf şeklinde bile anlayabiliyorum. Kodun kendini iyi açıkladığı gibi, hataların düzeltilip düzeltilemeyeceğini görmeye çalışın, muhtemelen başka bir giriş olmadığı için bu cevap seçilecektir.
Thanasis Papoutsidakis
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.