Chơi gôn trước C-golf của tôi


12

Lý lịch

Đối với bài nộp của tôi bằng C, tôi cần một công cụ xử lý. Giống như trong nhiều ngôn ngữ khác, khoảng trắng hầu như không liên quan đến nguồn C (nhưng không phải lúc nào cũng vậy!) - vẫn làm cho mã dễ hiểu hơn nhiều đối với con người. Một chương trình C được đánh gôn hoàn toàn không chứa một khoảng trắng dự phòng thường không thể đọc được.

Do đó, tôi thích viết mã của mình bằng C để gửi bao gồm cả khoảng trắng và đôi khi là các nhận xét, vì vậy chương trình giữ cấu trúc dễ hiểu trong khi viết. Bước cuối cùng là xóa tất cả các bình luận và khoảng trắng thừa. Đây là một công việc tẻ nhạt và không cần suy nghĩ mà thực sự nên được thực hiện bởi một chương trình máy tính.

Bài tập

Viết chương trình hoặc chức năng loại bỏ các bình luận và khoảng trắng dư thừa từ một số nguồn C "tiền golf" theo các quy tắc sau:

  • Một \(dấu gạch chéo ngược) là ký tự cuối cùng trong một dòng là một dòng tiếp tục . Nếu bạn tìm thấy điều này, bạn phải coi dòng sau là một phần của cùng một dòng logic (ví dụ bạn có thể loại bỏ hoàn toàn \và dòng sau \n(dòng mới) trước khi làm bất cứ điều gì khác)
  • Nhận xét sẽ chỉ sử dụng định dạng một dòng, bắt đầu bằng //. Vì vậy, để loại bỏ chúng, bạn bỏ qua phần còn lại của dòng logic bất cứ nơi nào bạn gặp //bên ngoài một chuỗi ký tự (xem bên dưới).
  • Các ký tự khoảng trắng là (dấu cách), \t(tab) và \n(dòng mới, vì vậy ở đây kết thúc một dòng logic).
  • Khi bạn tìm thấy một chuỗi các khoảng trắng, hãy kiểm tra các ký tự không phải khoảng trắng xung quanh nó. Nếu

    • cả hai đều là chữ và số hoặc gạch dưới (phạm vi [a-zA-Z0-9_]) hoặc
    • cả hai đều +hoặc
    • cả hai đều -hoặc
    • cái trước là /và cái sau là*

    sau đó thay thế chuỗi bằng một ký tự dấu cách ( ).

    Nếu không, loại bỏ hoàn toàn trình tự.

    Quy tắc này có một số ngoại lệ :

    • Các chỉ thị tiền xử lý phải xuất hiện trên các dòng riêng của chúng trong đầu ra của bạn. Một chỉ thị tiền xử lý là một dòng bắt đầu với #.
    • Bên trong một chuỗi ký tự hoặc ký tự , bạn không nên xóa bất kỳ khoảng trắng nào. Bất kỳ "(trích dẫn kép) / '(trích dẫn đơn) không được đặt trực tiếp trước một số dấu gạch chéo ngược ( \) bắt đầu hoặc kết thúc một chuỗi ký tự / ký tự . Bạn được đảm bảo rằng chuỗi ký tự và ký tự kết thúc trên cùng một dòng họ đã bắt đầu. chuỗi ký tựký tự ký tự không thể được lồng nhau, do đó, 'bên trong một chuỗi ký tự , cũng như "bên trong một ký tự chữ không có bất kỳ ý nghĩa đặc biệt nào.

Đặc tả I / O

Đầu vào và đầu ra phải là chuỗi ký tự (chuỗi) bao gồm các ký tự dòng mới hoặc mảng / danh sách các chuỗi không chứa ký tự dòng mới. Nếu bạn chọn sử dụng mảng / danh sách, mỗi phần tử đại diện cho một dòng, vì vậy các dòng mới sẽ ẩn sau mỗi phần tử.

Bạn có thể giả sử đầu vào là mã nguồn chương trình C hợp lệ. Điều này cũng có nghĩa là nó chỉ chứa các ký tự, tab và dòng mới ASCII có thể in được. Hành vi không xác định trên đầu vào không đúng định dạng được cho phép.

Hàng đầu và dấu khoảng trắng / dòng sản phẩm nào đang không được phép .

Các trường hợp thử nghiệm

  1. đầu vào

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

    đầu ra

    main(){printf("Hello, World!");}
    
  2. đầu vào

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

    đầu ra

    #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. đầu vào

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

    đầu ra

    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. đầu vào

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

    đầu ra

    x;
    #include<stdio.h>
    int main(){puts("hello // there");}
    
  5. đầu vào (một ví dụ thực tế)

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

    đầu ra

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

Đây là , vì vậy câu trả lời hợp lệ ngắn nhất (tính bằng byte) sẽ thắng.



Câu trả lời:


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 được tính bằng CP-1252 , ·mỗi byte là một byte. Lưu ý rằng điều này hy vọng mã C là một đối số dòng lệnh đơn, mà (trên một dòng lệnh thực tế) sẽ yêu cầu sử dụng các chuỗi thoát rất nhiều. Dễ dàng hơn nhiều khi dùng thử trực tuyến!

Giải thích về phiên bản hơi vô căn cứ

Mã này thực hiện một loạt các hoạt động thay thế, với một vài thủ thuật.

Tiếp tục dấu gạch chéo ngược

RMTất cả chúng ta đều xuất hiện chuỗi ký tự

"\
"

đó là dấu gạch chéo ngược theo dòng mới.

Chuỗi và ký tự chữ

Chúng tôi sử dụng thay thế regex với chức năng gọi lại:

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

{
 lPBa
 C(++i + 191)
}

Regex khớp với một trích dẫn đơn hoặc kép, theo sau là không tham lam .*?phù hợp với 0 hoặc nhiều ký tự, càng ít càng tốt. Chúng tôi có một cái nhìn tiêu cực để đảm bảo rằng nhân vật trước đó không phải là dấu gạch chéo ngược; sau đó chúng ta khớp một số dấu gạch chéo chẵn theo sau là dấu phân cách mở lại.

Hàm gọi lại lấy chuỗi / ký tự bằng chữ và đẩy nó vào phía sau danh sách l. Sau đó, nó trả về một ký tự bắt đầu bằng mã ký tự 192 ( À) và tăng dần với mỗi ký tự được thay thế. Do đó, mã được chuyển đổi như vậy:

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

printf(À, Á);

Các ký tự thay thế này được đảm bảo không xảy ra trong mã nguồn, điều đó có nghĩa là chúng ta có thể thay thế chúng một cách rõ ràng sau này.

Bình luận

`//.*`

x

Regex khớp //với tất cả mọi thứ cho đến dòng mới và thay thế bằng x(đặt trước chuỗi trống).

Các chỉ thị tiền xử lý

`#.*`

_WR'¶

Kết thúc tốt đẹp các ký tự không phải dòng mới bắt đầu bằng một dấu thăng .

Không gian không nên được loại bỏ

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

{
 a R w '·
}

Có rất nhiều thứ đang diễn ra ở đây. Phần đầu tiên tạo danh sách regexes này để thay thế:

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

Lưu ý việc sử dụng lookahead để khớp, ví dụ, chỉ e trong define P printf. Bằng cách đó, trận đấu này không tiêu thụ P, điều đó có nghĩa là trận đấu tiếp theo có thể sử dụng nó.

Chúng tôi tạo danh sách regexes này bằng cách ánh xạ một hàm vào danh sách, trong đó danh sách chứa

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

và hàm thực hiện điều này cho từng phần tử:

(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

Khi chúng tôi có biểu thức chính của mình, chúng tôi thay thế các lần xuất hiện của chúng bằng chức năng gọi lại này:

{aRw'·}

thay thế việc chạy khoảng trắng trong mỗi trận đấu với ·.

Loại bỏ khoảng trắng và dọn dẹp

[w `¶+` '·]

[x n s]

Ba thay thế liên tiếp thay thế các lần chạy còn lại của khoảng trắng ( w) cho chuỗi rỗng ( x), chạy cho dòng mới và ·cho không gian.

Thay thế lại chuỗi ký tự và ký tự

C(192+,#l)

l

Chúng tôi xây dựng một danh sách tất cả các ký tự mà chúng tôi sử dụng thay thế cho chữ bằng cách lấy 192 + range(len(l))và chuyển đổi thành ký tự. Sau đó chúng ta có thể thay thế từng cái bằng chữ nghĩa của nó l.

Và đó là nó! Chuỗi kết quả được tự động in.


Tuyệt vời, tôi rất ấn tượng (+1)! Bao gồm một //bên trong một chuỗi ký tự chắc chắn là một ý tưởng tốt cho một trường hợp thử nghiệm, tôi sẽ thêm một chuỗi vào ngày mai.
Felix Palmen

Uhm ... bây giờ tôi cũng tìm thấy một lỗi tinh vi ở đây ...
Felix Palmen

Tôi sẽ chọn một người chiến thắng sau 14 ngày (cuối tuần sau) và giải pháp của bạn sẽ là ứng cử viên đầu tiên nếu bạn có thời gian để sửa lỗi này. Ngay bây giờ, bạn có số điểm thấp nhất :)
Felix Palmen

1
@FelixPalmen Đã sửa!
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

Hãy thử trực tuyến!

Đây là rất nhiều niềm vui để viết! Đầu tiên, fhàm đi qua và loại bỏ tất cả các dấu gạch chéo ở cuối dòng sau đó lineschia nó thành một danh sách các chuỗi ở dòng mới. Sau đó, chúng tôi ánh xạ một loạt các chức năng lên các dòng và nối chúng lại với nhau. Những chức năng: dải khoảng trắng từ bên trái ( t) và từ bên phải ( r.t.rnơi rreverse); xóa khoảng trắng từ giữa, bỏ qua chuỗi ký tự và ký tự cũng như xóa nhận xét ( w); và cuối cùng thêm một ký tự dòng mới vào cuối nếu dòng bắt đầu bằng #. Sau khi tất cả các dòng được nối lại với nhau, hãy gtìm # ký tự và đảm bảo chúng được đặt trước một dòng mới.

wlà một chút phức tạp vì vậy tôi sẽ giải thích thêm. Đầu tiên tôi kiểm tra "//" vì trong wtôi biết tôi không ở trong một chuỗi ký tự, tôi biết đây là một nhận xét nên tôi bỏ phần còn lại của dòng. Tiếp theo tôi kiểm tra xem phần đầu có phải là dấu phân cách cho một chuỗi hoặc ký tự không. Nếu tôi chuẩn bị trước và chuyển dùi cui lchạy qua các ký tự, theo dõi trạng thái "thoát" nsẽ đúng nếu có một số chém liên tiếp chẵn. Khi lphát hiện dấu phân cách và không ở trạng thái thoát, nó chuyển dùi cui trở lại w, cắt xén để loại bỏ khoảng trắng sau nghĩa đen vì why vọng ký tự đầu tiên không phải là khoảng trắng. Khi nàowkhông tìm thấy dấu phân cách mà nó sử dụng span để tìm khoảng trắng ở đuôi. Nếu có bất cứ thứ gì nó kiểm tra xem các ký tự xung quanh nó có thể không được tiếp xúc và chèn một khoảng trắng nếu có. Sau đó, nó tái diễn sau khi khoảng trắng kết thúc. Nếu không có khoảng trắng thì không có khoảng trống nào được chèn vào và dù sao nó cũng di chuyển.

EDIT: Cảm ơn rất nhiều đến @DLosc vì đã chỉ ra một lỗi trong chương trình của tôi mà thực sự đã dẫn đến một cách để tôi rút ngắn nó! Hoan hô cho phù hợp với mô hình!

EDIT2: Tôi là một thằng ngốc không đọc xong thông số! Cảm ơn một lần nữa DLosc đã chỉ ra điều đó!

EDIT3: Chỉ cần nhận thấy một số điều giảm loại gây phiền nhiễu mà quay e=elemvào Char->[Char]->Boolđối với một số lý do, do đó phá vỡ trên e[a,q]. Tôi đã phải thêm một chữ ký loại để buộc nó là chính xác. Có ai biết làm thế nào tôi có thể sửa nó? Tôi chưa bao giờ gặp vấn đề này ở Haskell trước đây. TIO

EDIT4: sửa lỗi nhanh @FelixPalmen cho tôi xem. Tôi có thể cố gắng đánh nó xuống sau khi tôi có thời gian.

EDIT5: -24 byte nhờ @Lynn! Cảm ơn bạn! Tôi không biết bạn có thể chỉ định mọi thứ trên phạm vi toàn cầu bằng cách sử dụng khớp mẫu như thế n:c:z=...thật tuyệt! Ngoài ra ý tưởng tốt làm cho một nhà điều hành cho elemmong muốn tôi nghĩ về điều đó.



2
Bạn đang chạy vào giới hạn đơn hình đáng sợ ; xác định e x y=elem x y(hoặc thậm chí e x=elem x) giải quyết vấn đề của bạn. (Tôi đã đổi tên thành emột nhà điều hành (!),.)
Lynn

3

C, 497 494 490 489 byte

Vì chúng tôi đang xử lý C, hãy sử dụng C! Hàm f()lấy đầu vào từ con trỏ char pvà đầu ra thành con trỏ qvà giả sử rằng đầu vào nằm trong 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)();}

Chúng tôi giả định rằng tệp được định dạng tốt - chuỗi ký tự và ký tự được đóng và nếu có một nhận xét về dòng cuối cùng, thì phải có một dòng mới để đóng nó.

Giải trình

Phiên bản trước khi chơi golf chỉ dễ đọc hơn một chút, tôi sợ:

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

Nó thực hiện một máy trạng thái bằng cách đệ quy đuôi. Các macro và biến helper là

  • Ocho o utput
  • Rđể r ead đầu vàor
  • Vđể xác định v alid ký tự định danh (kể từ !isalnum('_'))
  • pq- Con trỏ I / O như mô tả
  • r- ký tự cuối cùng là r ead
  • s- s aved nhân vật không khoảng trắng gần đây
  • t- t ag khi làm việc trên một chỉ thị tiền xử lý

Nhà nước của chúng tôi là

  • a() - mã C bình thường
  • b() - chuỗi chữ
  • c() - bình luận
  • d() - Mã C bình thường, sau khi đọc r
  • e() - trình tự thoát
  • f() - trạng thái ban đầu (chức năng chính)
  • g() - trong khoảng trắng
  • h()- trong khoảng trắng - gửi đến g()hoặci()
  • i() - ngay sau khoảng trắng - chúng ta có cần chèn một ký tự khoảng trắng không?
  • j() - khoảng trắng ban đầu - không bao giờ chèn ký tự khoảng trắng

Chương trình kiểm tra

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

Điều này tạo ra

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

Giới hạn

Điều này phá vỡ các định nghĩa như

#define A (x)

bằng cách loại bỏ không gian phân tách tên khỏi mở rộng, cho

#define A(x)

với một ý nghĩa hoàn toàn khác. Trường hợp này vắng mặt trong các bộ thử nghiệm, vì vậy tôi sẽ không giải quyết nó.

Tôi nghi ngờ tôi có thể tạo ra một phiên bản ngắn hơn với chuyển đổi tại chỗ nhiều lượt - tôi có thể thử vào tuần tới.


Bạn có thể lưu một byte bằng cách xóa phần =cuối của định nghĩa Ovà thay đổi khoảng trắng theo sau mỗi cuộc gọi Othành a =.
Zacharý

Điều này thật tuyệt;) Về "giới hạn", hãy xem thêm nhận xét của tôi về chính câu hỏi - phát hiện điều này sẽ thêm quá nhiều phức tạp.
Felix Palmen

@Zachary - cảm ơn vì điều đó - Tôi đã quên khi tôi thay đổi mã chung thành đặc trưng ASCII O'\\'O' 'cả hai đều có được một khoảng trắng .
Toby Speight


2

C,  705   663  640 byte

Cảm ơn @ Zacharý vì đã chơi golf 40 byte và cảm ơn @Nahuel Fouilleul vì đã chơi 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;}

Hãy thử trực tuyến!


Có thể for(;W;C++){}trở thành for(;W;C++);?
Zacharý

@ Zacharý mà không bao giờ được yêu cầu. Đây là một công cụ cho bước cuối cùng: loại bỏ khoảng trắng và bình luận dư thừa.
Felix Palmen

Tôi đã đề cập đến mã của anh ấy, không phải là thách thức.
Zacharý

@ Zacharý haha ​​Tôi thấy ... kỳ lạ khi mã và đầu vào là cùng một ngôn ngữ;)
Felix Palmen

Điều này sẽ làm việc cho 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/./

Dùng thử trực tuyến


Có tôi chỉ đặt một giải pháp không tối ưu. Tôi vừa thêm liên kết tio, tôi sẽ tìm đến golf khi có thời gian.
Nahuel Fouilleul

Chỉ thị tiền xử lý nằm trên dòng riêng của chúng khi được đặt trước mã, như trong các trường hợp thử nghiệm, tuy nhiên nếu cần, tôi sẽ thêm thay đổi
Nahuel Fouilleul

1
sửa lỗi xem cập nhật
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'++ -- /*']

Hãy thử trực tuyến!

Chỉnh sửa: Cố định để bao gồm - -, + +/ *

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.