Golf saya "pra-golf" C

12

Latar Belakang

Untuk pengiriman di C, saya memerlukan alat pemrosesan. Seperti di banyak bahasa lain, spasi putih sebagian besar tidak relevan dalam sumber C (tetapi tidak selalu!) - masih membuat kode jauh lebih mudah dipahami oleh manusia. Program C sepenuhnya golf yang tidak mengandung spasi kosong tunggal sering hampir tidak dapat dibaca.

Oleh karena itu, saya suka menulis kode saya dalam C untuk pengiriman termasuk spasi dan kadang-kadang komentar, sehingga program membuat struktur yang komprehensif saat menulis. Langkah terakhir adalah menghapus semua komentar dan spasi kosong yang berlebihan. Ini adalah tugas yang membosankan dan tidak ada artinya yang harus dilakukan oleh magang program komputer.

Tugas

Tulis program atau fungsi yang menghilangkan komentar dan ruang kosong berlebihan dari beberapa sumber C "pra-golf" sesuai dengan aturan berikut:

  • A \(garis miring terbalik) sebagai karakter terakhir dalam sebuah garis adalah garis lanjutan . Jika Anda menemukan ini, Anda harus memperlakukan baris berikut sebagai bagian dari baris logis yang sama (misalnya, Anda dapat menghapus \dan mengikuti \n(baris baru) sepenuhnya sebelum melakukan hal lain)
  • Komentar hanya akan menggunakan format satu baris, dimulai dengan //. Jadi untuk menghapusnya, Anda mengabaikan sisa baris logis di mana pun Anda menemukan di //luar string literal (lihat di bawah).
  • Karakter spasi adalah (spasi), \t(tab) dan \n(baris baru, jadi di sini akhir dari baris logis).
  • Saat Anda menemukan urutan spasi putih, periksa karakter non-spasi putih di sekitarnya. Jika

    • keduanya adalah alfanumerik atau garis bawah (kisaran [a-zA-Z0-9_]) atau
    • keduanya +atau
    • keduanya -atau
    • yang sebelumnya adalah /dan yang berikutnya adalah*

    lalu ganti urutannya dengan karakter spasi tunggal ( ).

    Jika tidak, hilangkan urutan sepenuhnya.

    Aturan ini memiliki beberapa pengecualian :

    • Arahan preprosesor harus muncul pada baris mereka sendiri di output Anda. Arahan preprosesor adalah garis yang dimulai dengan #.
    • Di dalam string literal atau karakter literal , Anda tidak harus menghapus spasi kosong. Setiap "(tanda kutip ganda) / '(tanda kutip tunggal) yang tidak secara langsung didahului dengan jumlah garis miring terbalik yang aneh ( \) memulai atau mengakhiri string literal / karakter literal . Anda dijamin bahwa string dan karakter literal berakhir pada baris yang sama dengan yang mereka mulai. string literal dan literal karakter tidak dapat disarangkan, jadi 'di dalam string literal , serta "di dalam literal karakter tidak memiliki arti khusus.

Spesifikasi I / O

Input dan output harus berupa urutan karakter (string) termasuk karakter baris baru atau array / daftar string yang tidak mengandung karakter baris baru. Jika Anda memilih untuk menggunakan array / daftar, setiap elemen mewakili sebuah baris, sehingga baris baru tersirat setelah setiap elemen.

Anda dapat menganggap input tersebut adalah kode sumber program C yang valid. Ini juga berarti hanya berisi karakter, tab, dan baris ASCII yang dapat dicetak. Perilaku yang tidak terdefinisi pada input yang salah diijinkan.

Terkemuka dan trailing spasi / baris kosong yang tidak diperbolehkan .

Uji kasus

  1. memasukkan

    main() {
        printf("Hello, World!"); // hi
    }
    

    keluaran

    main(){printf("Hello, World!");}
    
  2. memasukkan

    #define max(x, y) \
        x > y ? x : y
    #define I(x) scanf("%d", &x)
    a;
    b; // just a needless comment, \
            because we can!
    main()
    {
        I(a);
        I(b);
        printf("\" max \": %d\n", max(a, b));
    }
    

    keluaran

    #define max(x,y)x>y?x:y
    #define I(x)scanf("%d",&x)
    a;b;main(){I(a);I(b);printf("\" max \": %d\n",max(a,b));}
    
  3. memasukkan

    x[10];*c;i;
    main()
    {
        int _e;
        for(; scanf("%d", &x) > 0 && ++_e;);
        for(c = x + _e; c --> x; i = 100 / *x, printf("%d ", i - --_e));
    }
    

    keluaran

    x[10];*c;i;main(){int _e;for(;scanf("%d",&x)>0&&++_e;);for(c=x+_e;c-->x;i=100/ *x,printf("%d ",i- --_e));}
    
  4. memasukkan

    x;
    #include <stdio.h>
    int main()
    {
        puts("hello // there");
    }
    

    keluaran

    x;
    #include<stdio.h>
    int main(){puts("hello // there");}
    
  5. input (contoh dunia nyata)

    // often used functions/keywords:
    #define P printf(
    #define A case
    #define B break
    
    // loops for copying rows upwards/downwards are similar -> macro
    #define L(i, e, t, f, s) \
            for (o=i; o e;){ strcpy(l[o t], l[o f]); c[o t]=c[s o]; }
    
    // range check for rows/columns is similar -> macro
    #define R(m,o) { return b<1|b>m ? m o : b; }
    
    // checking for numerical input is needed twice (move and print command):
    #define N(f) sscanf(f, "%d,%d", &i, &j) || sscanf(f, ",%d", &j)
    
    // room for 999 rows with each 999 cols (not specified, should be enough)
    // also declare "current line pointers" (*L for data, *C for line length),
    // an input buffer (a) and scratch variables
    r, i, j, o, z, c[999], *C, x=1, y=1;
    char a[999], l[999][999], (*L)[999];
    
    // move rows down from current cursor position
    D()
    {
        L(r, >y, , -1, --)
        r++ ? strcpy(l[o], l[o-1]+--x), c[o-1]=x, l[o-1][x]=0 : 0;
        c[y++] = strlen(l[o]);
        x=1;
    }
    
    // move rows up, appending uppermost to current line
    U()
    {
        strcat(*L, l[y]);
        *C = strlen(*L);
        L(y+1, <r, -1, , ++)
        --r;
        *l[r] = c[r] = 0;
    }
    
    // normalize positions, treat 0 as max
    X(b) R(c[y-1], +1)
    Y(b) R(r, )
    
    main()
    {
        for(;;) // forever
        {
            // initialize z as current line index, the current line pointers,
            // i and j for default values of positioning
            z = i = y;
            L = l + --z;
            C = c + z;
            j = x;
    
            // prompt:
            !r || y/r && x > *C
                ? P "end> ")
                : P "%d,%d> ", y, x);
    
            // read a line of input (using scanf so we don't need an include)
            scanf("%[^\n]%*c", a)
    
                // no command arguments -> make check easier:
                ? a[2] *= !!a[1],
    
                // numerical input -> have move command:
                // calculate new coordinates, checking for "relative"
                N(a)
                    ? y = Y(i + (i<0 | *a=='+') * y)
                        , x = X(j + (j<0 || strchr(a+1, '+')) * x)
                    :0
    
                // check for empty input, read single newline
                // and perform <return> command:
                : ( *a = D(), scanf("%*c") );
    
            switch(*a)
            {
                A 'e':
                    y = r;
                    x = c[r-1] + 1;
                    B;
    
                A 'b':
                    y = 1;
                    x = 1;
                    B;
    
                A 'L':
                    for(o = y-4; ++o < y+2;)
                        o<0 ^ o<r && P "%c%s\n", o^z ? ' ' : '>', l[o]);
                    for(o = x+1; --o;)
                        P " ");
                    P "^\n");
                    B;
    
                A 'l':
                    puts(*L);
                    B;
    
                A 'p':
                    i = 1;
                    j = 0;
                    N(a+2);
                    for(o = Y(i)-1; o<Y(j); ++o)
                        puts(l[o]);
                    B;
    
                A 'A':
                    y = r++;
                    strcpy(l[y], a+2);
                    x = c[y] = strlen(a+2);
                    ++x;
                    ++y;
                    B;
    
                A 'i':
                    D();
                    --y;
                    x=X(0);
                    // Commands i and r are very similar -> fall through
                    // from i to r after moving rows down and setting
                    // position at end of line:
    
                A 'r':
                    strcpy(*L+x-1, a+2);
                    *C = strlen(*L);
                    x = 1;
                    ++y > r && ++r;
                    B;
    
                A 'I':
                    o = strlen(a+2);
                    memmove(*L+x+o-1, *L+x-1, *C-x+1);
                    *C += o;
                    memcpy(*L+x-1, a+2, o);
                    x += o;
                    B;
    
                A 'd':
                    **L ? **L = *C = 0, x = 1 : U();
                    y = y>r ? r : y;
                    B;
    
                A 'j':
                    y<r && U();
            }
        }
    }
    

    keluaran

    #define P printf(
    #define A case
    #define B break
    #define L(i,e,t,f,s)for(o=i;o e;){strcpy(l[o t],l[o f]);c[o t]=c[s o];}
    #define R(m,o){return b<1|b>m?m o:b;}
    #define N(f)sscanf(f,"%d,%d",&i,&j)||sscanf(f,",%d",&j)
    r,i,j,o,z,c[999],*C,x=1,y=1;char a[999],l[999][999],(*L)[999];D(){L(r,>y,,-1,--)r++?strcpy(l[o],l[o-1]+--x),c[o-1]=x,l[o-1][x]=0:0;c[y++]=strlen(l[o]);x=1;}U(){strcat(*L,l[y]);*C=strlen(*L);L(y+1,<r,-1,,++)--r;*l[r]=c[r]=0;}X(b)R(c[y-1],+1)Y(b)R(r,)main(){for(;;){z=i=y;L=l+--z;C=c+z;j=x;!r||y/r&&x>*C?P"end> "):P"%d,%d> ",y,x);scanf("%[^\n]%*c",a)?a[2]*=!!a[1],N(a)?y=Y(i+(i<0|*a=='+')*y),x=X(j+(j<0||strchr(a+1,'+'))*x):0:(*a=D(),scanf("%*c"));switch(*a){A'e':y=r;x=c[r-1]+1;B;A'b':y=1;x=1;B;A'L':for(o=y-4;++o<y+2;)o<0^o<r&&P"%c%s\n",o^z?' ':'>',l[o]);for(o=x+1;--o;)P" ");P"^\n");B;A'l':puts(*L);B;A'p':i=1;j=0;N(a+2);for(o=Y(i)-1;o<Y(j);++o)puts(l[o]);B;A'A':y=r++;strcpy(l[y],a+2);x=c[y]=strlen(a+2);++x;++y;B;A'i':D();--y;x=X(0);A'r':strcpy(*L+x-1,a+2);*C=strlen(*L);x=1;++y>r&&++r;B;A'I':o=strlen(a+2);memmove(*L+x+o-1,*L+x-1,*C-x+1);*C+=o;memcpy(*L+x-1,a+2,o);x+=o;B;A'd':**L?**L=*C=0,x=1:U();y=y>r?r:y;B;A'j':y<r&&U();}}}
    

Ini , jadi jawaban tersingkat (dalam byte) yang valid akan menang.

Felix Palmen
sumber
terkait , terkait
HyperNeutrino

Jawaban:

4

Pip , 148 135 133 138 byte

aRM"\
"R`("|').*?(?<!\\)(\\\\)*\1`{lPBaC:++i+191}R[`//.*``#.*`{X*aJw.`(?=`}.')M[A`\w`RL2"++""--""/*"]w`¶+`'·C(192+,#l)][x_WR'¶{aRw'·}xnsl]

Byte dihitung dalam CP-1252 , jadi dan ·masing-masing satu byte. Perhatikan bahwa ini mengharapkan kode C sebagai argumen baris perintah tunggal, yang (pada baris perintah aktual) akan membutuhkan penggunaan urutan melarikan diri yang berlebihan. Ini jauh lebih mudah di Coba online!

Penjelasan dari versi yang sedikit tidak diubah

Kode melakukan banyak operasi penggantian, dengan beberapa trik.

Kelanjutan backslash

Kita RMsemua kemunculan string literal

"\
"

yaitu, garis miring terbalik diikuti oleh baris baru.

String dan karakter literal

Kami menggunakan pengganti regex dengan fungsi panggilan balik:

`("|').*?(?<!\\)(\\\\)*\1`

{
 lPBa
 C(++i + 191)
}

Regex cocok dengan kutipan tunggal atau ganda, diikuti oleh non-serakah .*?yang cocok dengan 0 atau lebih karakter, sesedikit mungkin. Kami memiliki pandangan negatif di belakang untuk memastikan bahwa karakter sebelumnya bukan backslash; kemudian kami mencocokkan jumlah backslash yang rata diikuti oleh pembatas pembukaan lagi.

Fungsi panggilan balik mengambil string / karakter literal dan mendorongnya ke bagian belakang daftar l. Kemudian mengembalikan karakter yang dimulai dengan kode karakter 192 ( À) dan meningkat dengan setiap literal diganti. Dengan demikian, kode ditransformasikan seperti:

printf("%c", '\'');

printf(À, Á);

Karakter pengganti ini dijamin tidak akan muncul dalam kode sumber, yang berarti kita dapat secara tak-gamblang menggantikan mereka nanti.

Komentar

`//.*`

x

Regex cocok dengan //semuanya hingga baris baru dan diganti dengan x(preset ke string kosong).

Arahan preprosesor

`#.*`

_WR'¶

Membungkus menjalankan karakter non-baris baru dimulai dengan masuk pound .

Ruang yang seharusnya tidak dihilangkan

{
 (
  X*a J w.`(?=`
 ) . ')
}
M
[
 A`\w` RL 2
 "++"
 "--"
 "/*"
]

{
 a R w '·
}

Ada banyak hal yang terjadi di sini. Bagian pertama menghasilkan daftar regex ini untuk menggantikan:

[
 `(?a)\w\s+(?=(?a)\w)`  Whitespace surrounded by [a-zA-Z_]
 `\+\s+(?=\+)`          Whitespace surrounded by +
 `\-\s+(?=\-)`          Whitespace surrounded by -
 `\/\s+(?=\*)`          Whitespace surrounded by / *
]

Perhatikan penggunaan lookaheads untuk mencocokkan, misalnya, hanya e di define P printf. Dengan begitu pertandingan ini tidak mengkonsumsi P, yang berarti pertandingan selanjutnya dapat menggunakannya.

Kami membuat daftar regex ini dengan memetakan fungsi ke daftar, di mana daftar berisi

[
 [`(?a)\w` `(?a)\w`]
 "++"
 "--"
 "/*"
]

dan fungsi melakukan ini untuk setiap elemen:

(X*aJw.`(?=`).')
 X*a              Map unary X to elements/chars a: converts to regex, escaping as needed
                  Regexes like `\w` stay unchanged; strings like "+" become `\+`
    J             Join the resulting list on:
     w             Preset variable for `\s+`
      .`(?=`       plus the beginning of the lookahead syntax
(           ).')  Concatenate the closing paren of the lookahead

Setelah kami memiliki regex kami, kami mengganti kemunculannya dengan fungsi callback ini:

{aRw'·}

yang menggantikan menjalankan spasi putih di setiap pertandingan dengan ·.

Penghapusan dan pembersihan spasi putih

[w `¶+` '·]

[x n s]

Tiga penggantian berturut-turut menggantikan sisa spasi ( w) untuk string kosong ( x), berjalan untuk baris baru, dan ·untuk ruang.

Substitusi kembali string dan karakter literal

C(192+,#l)

l

Kami menyusun daftar semua karakter yang kami gunakan sebagai pengganti literal dengan mengambil 192 + range(len(l))dan mengonversi ke karakter. Kami kemudian dapat mengganti masing-masing dengan literal terkait di l.

Dan itu dia! String yang dihasilkan dicetak secara otomatis.

DLosc
sumber
Hebat, saya terkesan (+1)! Termasuk //di dalam string literal jelas merupakan ide yang bagus untuk kasus uji, saya akan menambahkan satu besok.
Felix Palmen
Uhm ... sekarang saya menemukan bug halus di sini juga ...
Felix Palmen
Saya akan memilih seorang pemenang setelah 14 hari (akhir minggu depan) dan solusi Anda akan menjadi kandidat pertama jika Anda menemukan waktu untuk memperbaiki bug ini. Saat ini, Anda memiliki skor terendah :)
Felix Palmen
1
@FelixPalmen Diperbaiki!
DLosc
7

Haskell , 327 360 418 394 byte

g.(m.w.r.r=<<).lines.f
n:c:z="\n#_0123456789"++['A'..'Z']++['a'..'z']
(!)x=elem x
f('\\':'\n':a)=f a
f(a:b)=a:f b
f a=a
m('#':a)=c:a++[n]
m a=a
g(a:'#':b)=a:[n|a/=n]++c:g b
g(a:b)=a:g b
g a=a
s=span(!" \t")
r=reverse.snd.s
l n(a:b)d|a==d,n=a:w(snd$s b)|1>0=a:l(not$n&&a=='\\')b d
w('/':'/':_)=[]
w(a:b)|a!"\"'"=a:l(1>0)b a|(p,q:u)<-s b=a:[' '|p>"",a!z&&q!z||[a,q]!words"++ -- /*"]++w(q:u)
w a=a

Cobalah online!

Ini sangat menyenangkan untuk ditulis! Pertama ffungsi datang dan menghapus semua garis miring terbalik di akhir baris kemudian linesmemecahnya menjadi daftar string di baris baru. Lalu kami memetakan banyak fungsi ke baris dan menyatukan semuanya kembali. Fungsi-fungsi: Strip spasi dari kiri ( t) dan dari kanan ( r.t.rdi mana radalah reverse); menghapus spasi putih dari tengah, mengabaikan string dan karakter literal serta menghapus komentar ( w); dan akhirnya menambahkan karakter baris baru ke akhir jika baris dimulai dengan #. Setelah semua baris digabungkan kembali gmencari karakter # dan memastikan mereka didahului oleh baris baru.

wsedikit rumit jadi saya akan jelaskan lebih lanjut. Pertama saya periksa "//" karena di wsaya tahu saya tidak dalam string literal saya tahu ini adalah komentar jadi saya meninggalkan sisa baris. Selanjutnya saya periksa apakah head adalah pembatas untuk string atau karakter literal. Jika itu saya prepend itu dan meneruskan tongkat lyang berjalan melalui karakter, melacak keadaan "melarikan diri" dengan nyang akan benar jika ada sejumlah tebasan yang berurutan. Ketika lmendeteksi pembatas dan tidak dalam keadaan lolos ia melewati tongkat kembali ke w, memotong untuk menghilangkan spasi setelah literal karena wmengharapkan karakter pertama untuk tidak menjadi spasi. Kapanwtidak menemukan pembatas yang digunakan span untuk mencari spasi putih di bagian ekor. Jika ada yang memeriksa apakah karakter di sekitarnya tidak dapat dihubungi dan memasukkan spasi jika demikian. Kemudian muncul kembali setelah spasi putih berakhir. Jika tidak ada spasi putih tidak ada ruang yang dimasukkan dan itu akan tetap bergerak.

EDIT: Terima kasih banyak kepada @DLosc karena telah menunjukkan bug di program saya yang sebenarnya mengarah ke cara bagi saya untuk mempersingkat juga! Hore untuk pencocokan pola!

EDIT2: Saya idiot yang tidak selesai membaca spek! Terima kasih sekali lagi DLosc untuk menunjukkan hal itu!

EDIT3: Hanya melihat beberapa hal pengurangan tipe yang mengganggu yang berubah e=elem menjadi Char->[Char]->Boolkarena suatu alasan, sehingga terus berlanjut e[a,q]. Saya harus menambahkan tanda tangan jenis untuk memaksanya menjadi benar. Adakah yang tahu bagaimana saya bisa memperbaikinya? Saya belum pernah mengalami masalah ini di Haskell sebelumnya. TIO

EDIT4: perbaikan cepat untuk bug @FelixPalmen menunjukkan kepada saya. Saya mungkin akan mencoba menurunkannya nanti ketika saya punya waktu.

EDIT5: -24 byte terima kasih kepada @Lynn! Terima kasih! Saya tidak tahu Anda bisa menetapkan hal-hal pada lingkup global menggunakan pencocokan pola seperti n:c:z=...itu sangat keren! Juga ide bagus membuat operator untuk elemberharap aku memikirkan itu.

pengguna1472751
sumber
1
Saya memeras 24 byte .
Lynn
2
Anda mengalami pembatasan monomorfisme yang ditakuti ; mendefinisikan e x y=elem x y(atau bahkan e x=elem x) menyelesaikan masalah Anda. (Saya berganti nama emenjadi operator (!),.)
Lynn
3

C, 497 494 490 489 byte

Karena kita sedang memproses C, mari kita lakukan menggunakan C! Fungsi f()mengambil input dari char pointer pdan output ke pointer q, dan mengasumsikan bahwa input ada di ASCII:

#define O*q++
#define R (r=*p++)
#define V(c)(isalnum(c)||c==95)
char*p,*q,r,s,t;d(){isspace(r)?g():r==47&&*p==r?c(),g():r==92?e():(O=s=r)==34?b():r==39?O=R,a():r?a():(O=r);}a(){R;d();}b(){((O=R)==34?a:r==92?O=R,b:b)();}c(){while(R-10)p+=r==92;}e(){R-10?s=O=92,O=r,a():h();}j(){(!isspace(R)?r==47&&*p==r?c(),j:(t=r==35,d):j)();}f(){t=*p==35;j();}i(){V(s)&&V(r)||s==47&&r==42||(s==43||s==45)&&r==s&&*p==s?O=32:0;d();}h(){isspace(R)?g():i();}g(){(r==10?t?O=r,j:*p==35?s-10?s=O=r,j:0:h:h)();}

Kami berasumsi bahwa file tersebut terbentuk dengan baik - string dan karakter literal ditutup, dan jika ada komentar pada baris terakhir, harus ada baris baru untuk menutupnya.

Penjelasan

Versi pra-golf hanya sedikit lebih terbaca, saya khawatir:

#define O *q++=
#define R (r=*p++)
#define V(c)(isalnum(c)||c=='_')
char*p,*q,r,s,t;
d(){isspace(r)?g():r=='/'&&*p==r?c(),g():r=='\\'?e():(O s=r)=='"'?b():r=='\''?O R,a():r?a():(O r);}
a(){R;d();}
b(){((O R)=='"'?a:r=='\\'?O R,b:b)();}
c(){while(R!='\n')p+=r=='\\';}
e(){R!='\n'?s=O'\\',O r,a():h();}
j(){(!isspace(R)?r=='/'&&*p==r?c(),j:(t=r=='#',d):j)();}
f(){t=*p=='#';j();}
i(){V(s)&&V(r)||s=='/'&&r=='*'||(s=='+'||s=='-')&&r==s&&*p==s?O' ':0;d();}
h(){isspace(R)?g():i();}
g(){(r=='\n'?t?O r,j:*p=='#'?s!='\n'?s=O r,j:0:h:h)();}

Ini mengimplementasikan mesin negara dengan rekursi ekor. Makro dan variabel pembantu adalah

  • Ountuk o utput
  • Runtuk r ead masukan ker
  • Vuntuk menentukan v karakter pengenal alid (sejak !isalnum('_'))
  • pdan q- I / O pointer seperti yang dijelaskan
  • r- karakter terakhir menjadi r benar menyebalkan
  • s- s aved baru-baru ini karakter non-spasi
  • t- t ag ketika bekerja pada direktif preprocessor

Negara kami adalah

  • a() - kode C normal
  • b() - string literal
  • c() - komentar
  • d() - kode C normal, setelah membaca r
  • e() - urutan pelarian
  • f() - keadaan awal (fungsi utama)
  • g() - di ruang putih
  • h()- di ruang kosong - kirim ke g()ataui()
  • i() - segera setelah spasi - apakah kita perlu memasukkan karakter spasi?
  • j() - spasi awal - tidak pernah memasukkan karakter spasi

Program uji

#define DEMO(code)                              \
    do {                                        \
        char in[] = code;                       \
        char out[sizeof in];                    \
        p=in;q=out;f();                         \
        puts("vvvvvvvvvv");                     \
        puts(out);                              \
        puts("^^^^^^^^^^");                     \
    } while (0)

#include<stdio.h>
#include<stdlib.h>
int main()
{
    DEMO(
         "main() {\n"
         "    printf(\"Hello, World!\"); // hi\n"
         "}\n"
         );
    DEMO(
         "#define max(x, y)                               \\\n"
         "    x > y ? x : y\n"
         "#define I(x) scanf(\"%d\", &x)\n"
         "a;\n"
         "b; // just a needless comment, \\\n"
         "        because we can!\n"
         "main()\n"
         "{\n"
         "    I(a);\n"
         "    I(b);\n"
         "    printf(\"\\\" max \\\": %d\\n\", max(a, b));\n"
         "}\n"
         );
    DEMO(
         "x[10];*c;i;\n"
         "main()\n"
         "{\n"
         "    int _e;\n"
         "    for(; scanf(\"%d\", &x) > 0 && ++_e;);\n"
         "    for(c = x + _e; c --> x; i = 100 / *x, printf(\"%d \", i - --_e));\n"
         "}\n"
         );
    DEMO(
         "// often used functions/keywords:\n"
         "#define P printf(\n"
         "#define A case\n"
         "#define B break\n"
         "\n"
         "// loops for copying rows upwards/downwards are similar -> macro\n"
         "#define L(i, e, t, f, s) \\\n"
         "        for (o=i; o e;){ strcpy(l[o t], l[o f]); c[o t]=c[s o]; }\n"
         "\n"
         "// range check for rows/columns is similar -> macro\n"
         "#define R(m,o) { return b<1|b>m ? m o : b; }\n"
         "\n"
         "// checking for numerical input is needed twice (move and print command):\n"
         "#define N(f) sscanf(f, \"%d,%d\", &i, &j) || sscanf(f, \",%d\", &j)\n"
         "\n"
         "// room for 999 rows with each 999 cols (not specified, should be enough)\n"
         "// also declare \"current line pointers\" (*L for data, *C for line length),\n"
         "// an input buffer (a) and scratch variables\n"
         "r, i, j, o, z, c[999], *C, x=1, y=1;\n"
         "char a[999], l[999][999], (*L)[999];\n"
         "\n"
         "// move rows down from current cursor position\n"
         "D()\n"
         "{\n"
         "    L(r, >y, , -1, --)\n"
         "    r++ ? strcpy(l[o], l[o-1]+--x), c[o-1]=x, l[o-1][x]=0 : 0;\n"
         "    c[y++] = strlen(l[o]);\n"
         "    x=1;\n"
         "}\n"
         "\n"
         "// move rows up, appending uppermost to current line\n"
         "U()\n"
         "{\n"
         "    strcat(*L, l[y]);\n"
         "    *C = strlen(*L);\n"
         "    L(y+1, <r, -1, , ++)\n"
         "    --r;\n"
         "    *l[r] = c[r] = 0;\n"
         "}\n"
         "\n"
         "// normalize positions, treat 0 as max\n"
         "X(b) R(c[y-1], +1)\n"
         "Y(b) R(r, )\n"
         "\n"
         "main()\n"
         "{\n"
         "    for(;;) // forever\n"
         "    {\n"
         "        // initialize z as current line index, the current line pointers,\n"
         "        // i and j for default values of positioning\n"
         "        z = i = y;\n"
         "        L = l + --z;\n"
         "        C = c + z;\n"
         "        j = x;\n"
         "\n"
         "        // prompt:\n"
         "        !r || y/r && x > *C\n"
         "            ? P \"end> \")\n"
         "            : P \"%d,%d> \", y, x);\n"
         "\n"
         "        // read a line of input (using scanf so we don't need an include)\n"
         "        scanf(\"%[^\\n]%*c\", a)\n"
         "\n"
         "            // no command arguments -> make check easier:\n"
         "            ? a[2] *= !!a[1],\n"
         "\n"
         "            // numerical input -> have move command:\n"
         "            // calculate new coordinates, checking for \"relative\"\n"
         "            N(a)\n"
         "                ? y = Y(i + (i<0 | *a=='+') * y)\n"
         "                    , x = X(j + (j<0 || strchr(a+1, '+')) * x)\n"
         "                :0\n"
         "\n"
         "            // check for empty input, read single newline\n"
         "            // and perform <return> command:\n"
         "            : ( *a = D(), scanf(\"%*c\") );\n"
         "\n"
         "        switch(*a)\n"
         "        {\n"
         "            A 'e':\n"
         "                y = r;\n"
         "                x = c[r-1] + 1;\n"
         "                B;\n"
         "\n"
         "            A 'b':\n"
         "                y = 1;\n"
         "                x = 1;\n"
         "                B;\n"
         "\n"
         "            A 'L':\n"
         "                for(o = y-4; ++o < y+2;)\n"
         "                    o<0 ^ o<r && P \"%c%s\\n\", o^z ? ' ' : '>', l[o]);\n"
         "                for(o = x+1; --o;)\n"
         "                    P \" \");\n"
         "                P \"^\\n\");\n"
         "                B;\n"
         "\n"
         "            A 'l':\n"
         "                puts(*L);\n"
         "                B;\n"
         "\n"
         "            A 'p':\n"
         "                i = 1;\n"
         "                j = 0;\n"
         "                N(a+2);\n"
         "                for(o = Y(i)-1; o<Y(j); ++o)\n"
         "                    puts(l[o]);\n"
         "                B;\n"
         "\n"
         "            A 'A':\n"
         "                y = r++;\n"
         "                strcpy(l[y], a+2);\n"
         "                x = c[y] = strlen(a+2);\n"
         "                ++x;\n"
         "                ++y;\n"
         "                B;\n"
         "\n"
         "            A 'i':\n"
         "                D();\n"
         "                --y;\n"
         "                x=X(0);\n"
         "                // Commands i and r are very similar -> fall through\n"
         "                // from i to r after moving rows down and setting\n"
         "                // position at end of line:\n"
         "\n"
         "            A 'r':\n"
         "                strcpy(*L+x-1, a+2);\n"
         "                *C = strlen(*L);\n"
         "                x = 1;\n"
         "                ++y > r && ++r;\n"
         "                B;\n"
         "\n"
         "            A 'I':\n"
         "                o = strlen(a+2);\n"
         "                memmove(*L+x+o-1, *L+x-1, *C-x+1);\n"
         "                *C += o;\n"
         "                memcpy(*L+x-1, a+2, o);\n"
         "                x += o;\n"
         "                B;\n"
         "\n"
         "            A 'd':\n"
         "                **L ? **L = *C = 0, x = 1 : U();\n"
         "                y = y>r ? r : y;\n"
         "                B;\n"
         "\n"
         "            A 'j':\n"
         "                y<r && U();\n"
         "        }\n"
         "    }\n"
         "}\n";);
}

Ini menghasilkan

main(){printf("Hello, World!");}
#define max(x,y)x>y?x:y
#define I(x)scanf("%d",&x)
a;b;main(){I(a);I(b);printf("\" max \": %d\n",max(a,b));}
x[10];*c;i;main(){int _e;for(;scanf("%d",&x)>0&&++_e;);for(c=x+_e;c-->x;i=100/ *x,printf("%d ",i- --_e));}
#define P printf(
#define A case
#define B break
#define L(i,e,t,f,s)for(o=i;o e;){strcpy(l[o t],l[o f]);c[o t]=c[s o];}
#define R(m,o){return b<1|b>m?m o:b;}
#define N(f)sscanf(f,"%d,%d",&i,&j)||sscanf(f,",%d",&j)
r,i,j,o,z,c[999],*C,x=1,y=1;char a[999],l[999][999],(*L)[999];D(){L(r,>y,,-1,--)r++?strcpy(l[o],l[o-1]+--x),c[o-1]=x,l[o-1][x]=0:0;c[y++]=strlen(l[o]);x=1;}U(){strcat(*L,l[y]);*C=strlen(*L);L(y+1,<r,-1,,++)--r;*l[r]=c[r]=0;}X(b)R(c[y-1],+1)Y(b)R(r,)main(){for(;;){z=i=y;L=l+--z;C=c+z;j=x;!r||y/r&&x>*C?P"end> "):P"%d,%d> ",y,x);scanf("%[^\n]%*c",a)?a[2]*=!!a[1],N(a)?y=Y(i+(i<0|*a=='+')*y),x=X(j+(j<0||strchr(a+1,'+'))*x):0:(*a=D(),scanf("%*c"));switch(*a){A'e':y=r;x=c[r-1]+1;B;A'b':y=1;x=1;B;A'L':for(o=y-4;++o<y+2;)o<0^o<r&&P"%c%s\n",o^z?' ' :'>',l[o]);for(o=x+1;--o;)P" ");P"^\n");B;A'l':puts(*L);B;A'p':i=1;j=0;N(a+2);for(o=Y(i)-1;o<Y(j);++o)puts(l[o]);B;A'A':y=r++;strcpy(l[y],a+2);x=c[y]=strlen(a+2);++x;++y;B;A'i':D();--y;x=X(0);A'r':strcpy(*L+x-1,a+2);*C=strlen(*L);x=1;++y>r&&++r;B;A'I':o=strlen(a+2);memmove(*L+x+o-1,*L+x-1,*C-x+1);*C+=o;memcpy(*L+x-1,a+2,o);x+=o;B;A'd':**L?**L=*C=0,x=1:U();y=y>r?r:y;B;A'j':y<r&&U();}}}

Batasan

Ini memecah definisi seperti

#define A (x)

dengan menghapus ruang yang memisahkan nama dari ekspansi, memberi

#define A(x)

dengan makna yang sama sekali berbeda. Kasing ini tidak ada di set tes, jadi saya tidak akan mengatasinya.

Saya kira saya mungkin dapat menghasilkan versi yang lebih pendek dengan konversi multi-pass in-place - saya mungkin akan mencobanya minggu depan.

Toby Speight
sumber
Anda dapat menyimpan satu byte dengan menghapus =di akhir definisi Odan mengubah ruang yang mengikuti setiap panggilan Omenjadi a =.
Zacharý
Ini hebat;) Tentang "batasan", lihat juga komentar saya pada pertanyaan itu sendiri - mendeteksi ini akan menambah terlalu banyak kerumitan.
Felix Palmen
@ Zachary - terima kasih untuk itu - Saya lupa ketika saya mengubah kode umum menjadi ASCII-spesifik O'\\'dan O' 'keduanya mendapatkan spasi.
Toby Speight
464 byte
ceilingcat
2

C,  705   663  640 byte

Terima kasih kepada @ Zacharý untuk bermain golf 40 byte dan terima kasih kepada @Nahuel Fouilleul untuk bermain golf 23 byte!

#define A(x)(x>47&x<58|x>64&x<91|x>96&x<123)
#define K if(*C==47&(C[1]==47|p==47)){if(p==47)--G;for(c=1;c;*C++-92||c++)*C-10||--c;if(d)p=*G++=10,--d;
#define D if(!d&*C==35){d=1;if(p&p-10)p=*G++=10;}
#define S K}if((A(p)&A(*C))|(p==*C&l==43|p==45)|p==47&*C==42|p==95&(A(*C)|*C==95)|*C==95&(A(p)|p==95))p=*G++=32;}
#define W*C<33|*C==92
#define F{for(;W;C++)
c,d,e,p,l;g(char*C,char*G)F;for(;*C;*C>32&&*C-34&&*C-39&&(p=*G++=*C),*C-34&&*C-39&&C++){l=e=0;if(*C==34)l=34;if(*C==39)l=39;if(l)for(*G++=l,p=*G++=*++C;*C++-l|e%2;e=*(C-1)-92?0:e+1)p=*G++=*C;K}D if(d){if(W)F{*C-92||++d;*C-10||--d;if(!d){p=*G++=10;goto E;}}S}else{if(W)F;S}E:D}*G=0;}

Cobalah online!

Steadybox
sumber
Dapat for(;W;C++){}menjadi for(;W;C++);?
Zacharý
@ Zacharý yang tidak pernah diminta. Ini adalah alat untuk langkah terakhir: hapus spasi dan komentar yang berlebihan.
Felix Palmen
Saya mengacu pada kode-nya, bukan tantangan.
Zacharý
@ Zacharý haha ​​saya melihat ... aneh ketika kode dan input adalah bahasa yang sama;)
Felix Palmen
Apakah ini akan bekerja untuk 665 byte? goo.gl/E6tk8V
Zacharý
2

Perl 5, 250 + 3 (-00n) , 167 + 1 (-p) byte

$_.=<>while s/\\
//;s,(//.*)|(("|')(\\.|.)*?\3)|/?[^"'/]+,$1|$2?$2:$&=~s@(\S?)\K\s+(?=(.?))@"$1$2"=~/\w\w|\+\+|--|\/\*/&&$"@ger,ge;$d++&&$l+/^#/&&s/^/
/,$l=/^#/m if/./

Cobalah online

Nahuel Fouilleul
sumber
Ya saya hanya menempatkan solusi yang tidak optimal. Saya baru saja menambahkan tautan tio, saya akan melihat ke golf ketika saya punya waktu.
Nahuel Fouilleul
arahan preprocessor berada pada baris mereka sendiri ketika ditempatkan sebelum kode, seperti dalam kasus uji namun jika diperlukan saya akan menambahkan perubahan
Nahuel Fouilleul
1
diperbaiki lihat pembaruan
Nahuel Fouilleul
0

Python 2 , 479 456 445 434 502 497 byte

e=enumerate
import re
u=re.sub
def f(s):
 r=()
 for l in u(r'\\\n','',s).split('\n'):
	s=p=w=0;L=[]
	for i,c in e(l):
	 if(p<1)*'//'==l[i:i+2]:l=l[:i]
	 if c in"'\""and w%2<1:
		if p in(c,0):L+=[l[s:i+1]];s=i+1
		p=[0,c][p<1]
	 w=[0,w+1]['\\'==c]
	r+=L+[l[s:]],
 S=''
 for l in r:s=''.join([u('. .',R,u('. .',R,u('\s+',' ',x))).strip(),x][i%2]for i,x in e(l));S+=['%s','\n%s\n'][s[:1]=='#']%s
 print u('\n\n','\n',S).strip()
def R(m):g=m.group(0);f=g[::2];return[f,g][f.isalnum()or f in'++ -- /*']

Cobalah online!

Edit: Tetap untuk memasukkan - -, + +, dan/ *

TFeld
sumber