Golf il mio “pre-golf” C


12

sfondo

Per i miei invii di in C, ho bisogno di uno strumento di elaborazione. Come in molte altre lingue, lo spazio bianco è per lo più irrilevante nella fonte C (ma non sempre!) - Rende ancora il codice molto più comprensibile per l'uomo. Un programma C completamente golfato che non contiene un singolo spazio ridondante spesso è a malapena leggibile.

Pertanto, mi piace scrivere il mio codice in C per una presentazione di includa spazi bianchi e talvolta commenti, quindi il programma mantiene una struttura comprensibile durante la scrittura. L'ultimo passaggio è rimuovere tutti i commenti e gli spazi bianchi ridondanti. Questo è un compito noioso e insensato che dovrebbe davvero essere svolto da uno stagista di un programma per computer.

Compito

Scrivi un programma o una funzione che elimini i commenti e gli spazi bianchi ridondanti da una sorgente C "pre-golf" secondo le seguenti regole:

  • Una \(barra rovesciata) come l'ultimo carattere di una riga è una continuazione di riga . Se lo trovi, devi considerare la seguente riga come parte della stessa riga logica (potresti ad esempio rimuovere completamente la \e la seguente \n(nuova riga) prima di fare qualsiasi altra cosa)
  • I commenti utilizzeranno solo il formato di una riga, a partire da //. Quindi, per rimuoverli, ignori il resto della linea logica ovunque incontri //fuori da una stringa letterale (vedi sotto).
  • I caratteri degli spazi bianchi sono (spazio), \t(tab) e \n(newline, quindi qui la fine di una linea logica).
  • Quando trovi una sequenza di spazi bianchi, esamina i caratteri non bianchi che lo circondano. Se

    • entrambi sono alfanumerici o di sottolineatura (intervallo [a-zA-Z0-9_]) o
    • entrambi sono +o
    • entrambi sono -o
    • quello che precede è /e quello che segue è*

    quindi sostituire la sequenza con un singolo carattere spazio ( ).

    Altrimenti, eliminare completamente la sequenza.

    Questa regola ha alcune eccezioni :

    • Le direttive del preprocessore devono apparire sulle proprie righe nell'output. Una direttiva preprocessore è una riga che inizia con #.
    • All'interno di una stringa letterale o letterale di carattere , non è necessario rimuovere spazi bianchi. Qualsiasi "(virgoletta doppia) / '(virgoletta singola) che non è preceduta direttamente da un numero dispari di barre rovesciate ( \) inizia o termina una stringa letterale / carattere letterale . Hai la certezza che i letterali di stringhe e caratteri finiscano sulla stessa linea da cui sono partiti. i letterali stringa e i caratteri letterali non possono essere nidificati, quindi un valore letterale' interno a una stringa , nonché "un valore letterale interno a un carattere non hanno alcun significato speciale.

Specifica I / O

L'input e l'output devono essere sequenze di caratteri (stringhe) inclusi caratteri di nuova riga o matrici / elenchi di stringhe che non contengono caratteri di nuova riga. Se si sceglie di utilizzare matrici / elenchi, ogni elemento rappresenta una linea, quindi le nuove righe sono implicite dopo ogni elemento.

È possibile supporre che l'input sia un codice sorgente valido del programma C. Questo significa anche che contiene solo caratteri ASCII stampabili, schede e nuove righe. È consentito un comportamento indefinito sull'input non valido.

Non sono consentiti spazi vuoti iniziali o finali / righe vuote .

Casi test

  1. ingresso

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

    produzione

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

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

    produzione

    #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. ingresso

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

    produzione

    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. ingresso

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

    produzione

    x;
    #include<stdio.h>
    int main(){puts("hello // there");}
    
  5. input (un esempio del mondo reale)

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

    produzione

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

Questo è , quindi vince la risposta più breve (in byte) valida.



Risposte:


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]

I byte vengono contati in CP-1252 , quindi e ·sono ciascuno un byte. Si noti che ciò prevede che il codice C sia un singolo argomento della riga di comando, che (su una riga di comando effettiva) richiederebbe l'uso di copiose sequenze di escape. È molto più facile provalo online!

Spiegazione della versione leggermente non golfata

Il codice esegue una serie di operazioni di sostituzione, con un paio di trucchi.

Continuazioni di barra rovesciata

Abbiamo RMtutte le occorrenze della stringa letterale

"\
"

cioè barra rovesciata seguita da newline.

Letterali di stringhe e caratteri

Utilizziamo una sostituzione regex con una funzione di callback:

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

{
 lPBa
 C(++i + 191)
}

La regex corrisponde a una virgoletta singola o doppia, seguita da una non avida .*?che corrisponde a 0 o più caratteri, il minor numero possibile. Abbiamo un aspetto negativo per garantire che il personaggio precedente non fosse una barra rovesciata; quindi abbiniamo un numero pari di barre rovesciate seguite di nuovo dal delimitatore di apertura.

La funzione di callback prende letteralmente la stringa / carattere e la spinge in fondo all'elenco l. Restituisce quindi un carattere che inizia con il codice carattere 192 ( À) e aumenta con ogni valore letterale sostituito. Pertanto, il codice viene trasformato in questo modo:

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

printf(À, Á);

Questi caratteri sostitutivi non sono garantiti nel codice sorgente, il che significa che possiamo sostituirli in modo inequivocabile in un secondo momento.

Commenti

`//.*`

x

Il regex corrisponde //più tutto fino alla nuova riga e lo sostituisce con x(preimpostato sulla stringa vuota).

Direttive del preprocessore

`#.*`

_WR'¶

Avvolge sequenze di caratteri non newline che iniziano con un cancelletto .

Spazi che non devono essere eliminati

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

{
 a R w '·
}

C'è molto da fare qui. La prima parte genera questo elenco di regex per sostituire:

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

Nota l'uso di lookaheads per abbinare, ad esempio, solo e in define P printf. In questo modo questa partita non consuma la P, il che significa che la prossima partita può usarla.

Generiamo questo elenco di regex mappando una funzione in un elenco, in cui l'elenco contiene

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

e la funzione fa questo ad ogni elemento:

(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

Una volta che abbiamo le nostre regex, sostituiamo le loro occorrenze con questa funzione di callback:

{aRw'·}

che sostituisce la corsa di spazi bianchi in ogni partita con ·.

Eliminazione e pulizia degli spazi bianchi

[w `¶+` '·]

[x n s]

Tre sostituzioni successive sostituiscono le rimanenti esecuzioni di spazi bianchi ( w) con stringhe vuote ( x), esecuzioni per newline e ·spazio.

Sostituzione sostitutiva dei letterali di stringhe e caratteri

C(192+,#l)

l

Costruiamo un elenco di tutti i personaggi che abbiamo usato come sostituzioni per i letterali prendendo 192 + range(len(l))e convertendo in caratteri. Possiamo quindi sostituire ognuno di questi con il letterale associato in l.

E questo è tutto! La stringa risultante viene stampata automaticamente.


Ottimo, sono impressionato (+1)! Includere un valore //letterale all'interno di una stringa è sicuramente una buona idea per un caso di test, ne aggiungerò uno domani.
Felix Palmen,

Uhm ... ora ho trovato anche un bug sottile qui ...
Felix Palmen,

Sceglierò un vincitore dopo 14 giorni (fine della prossima settimana) e la tua soluzione sarebbe il primo candidato se trovassi il tempo per correggere questo bug. In questo momento, hai il punteggio più basso :)
Felix Palmen

1
@FelixPalmen Risolto!
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

Provalo online!

È stato molto divertente scrivere! Innanzitutto la ffunzione viene eseguita e rimuove tutte le barre rovesciate alla fine delle righe, quindi la linessuddivide in un elenco di stringhe nelle nuove righe. Quindi mappiamo un gruppo di funzioni sulle linee e le concateniamo tutte insieme. Quelle funzioni: spoglia spazio bianco da sinistra ( t) e da destra ( r.t.rdove si rtrova reverse); rimuove gli spazi bianchi dal centro, ignorando i letterali di stringa e caratteri e rimuovendo i commenti ( w); e infine aggiunge un carattere di nuova riga alla fine se la linea inizia con un #. Dopo che tutte le linee sono state concatenate di nuovo insieme gcerca # caratteri e assicura che siano precedute da una nuova riga.

wè un po 'complesso, quindi lo spiegherò ulteriormente. Per prima cosa cerco "//" poiché in wso che non sono in una stringa letterale, so che questo è un commento, quindi lascio cadere il resto della riga. Quindi controllo se la testa è un delimitatore per una stringa o un carattere letterale. Se lo è, lo antepongo e passo il testimone al lquale scorre attraverso i personaggi, monitorando lo stato "fuga" con il nquale sarà vero se ci sono stati un numero pari di barre consecutive. Quando lrileva un delimitatore e non si trova nello stato di escape, passa di nuovo il testimone w, tagliandolo per eliminare gli spazi bianchi dopo il valore letterale perché si waspetta che il primo carattere non sia uno spazio bianco. quandownon trova un delimitatore che utilizza span per cercare spazi bianchi nella coda. Se ce n'è, controlla se i personaggi che lo circondano non possono essere messi in contatto e inserisce uno spazio in tal caso. Quindi ricorre al termine dello spazio bianco. Se non c'era spazio bianco, non viene inserito spazio e si sposta comunque.

EDIT: Grazie mille a @DLosc per aver segnalato un bug nel mio programma che in realtà mi ha permesso di accorciarlo! Evviva per la corrispondenza del modello!

EDIT2: Sono un idiota che non ha finito di leggere le specifiche! Grazie ancora DLosc per averlo segnalato!

EDIT3: ho appena notato alcune fastidiose cose sulla riduzione del tipo che si sono e=elemtrasformate Char->[Char]->Boolper qualche motivo, interrompendo così e[a,q]. Ho dovuto aggiungere una firma del tipo per costringerlo a essere corretto. Qualcuno sa come potrei risolverlo? Non ho mai avuto questo problema in Haskell prima. TIO

EDIT4: mi ha mostrato la soluzione rapida per il bug @FelixPalmen. Potrei provare a giocarci più tardi quando avrò del tempo.

EDIT5: -24 byte grazie a @Lynn! Grazie! Non sapevo che potessi assegnare cose sull'ambito globale usando la corrispondenza dei modelli come n:c:z=...se fosse davvero fantastico! Anche una buona idea fare un operatore per elemdesiderio ci avevo pensato.



2
Ti imbatti nella temuta restrizione del monomorfismo ; la definizione e x y=elem x y(o anche e x=elem x) risolve il problema. (Ho rinominato eoperatore (!)
Lynn,

3

C, 497 494 490 489 byte

Dato che stiamo elaborando C, facciamolo usando C! La funzione f()prende l'input dal puntatore char pe l'output al puntatore qe presuppone che l'input sia in 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)();}

Partiamo dal presupposto che il file sia ben formato: i letterali di stringhe e caratteri sono chiusi e se c'è un commento sull'ultima riga, ci deve essere una nuova riga per chiuderlo.

Spiegazione

La versione pre-golf è solo leggermente più leggibile, temo:

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

Implementa una macchina a stati mediante ricorsione della coda. Le macro e le variabili di supporto sono

  • Oper o utput
  • Ra r ead input inr
  • Vper determinare i caratteri identificativi v alid (poiché !isalnum('_'))
  • pe q- puntatori I / O come descritto
  • r- ultimo carattere per essere r ead
  • s- s recente carattere AVED non-spazio bianco
  • t- t ag quando si lavora su una direttiva del preprocessore

I nostri stati lo sono

  • a() - codice C normale
  • b() - stringa letterale
  • c() - commento
  • d() - normale codice C, dopo la lettura r
  • e() - sequenza di escape
  • f() - stato iniziale (funzione principale)
  • g() - negli spazi bianchi
  • h()- negli spazi bianchi - spedire a g()oi()
  • i() - subito dopo lo spazio bianco - dobbiamo inserire un carattere spazio?
  • j() - spazio iniziale bianco - non inserire mai un carattere spazio

Programma di test

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

Questo produce

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

Limitazione

Questo rompe definizioni come

#define A (x)

rimuovendo lo spazio che separa il nome dall'espansione, dando

#define A(x)

con un significato completamente diverso. Questo caso è assente dai set di test, quindi non ho intenzione di affrontarlo.

Ho il sospetto che potrei essere in grado di produrre una versione più breve con una conversione sul posto multi-pass - potrei provare quella settimana prossima.


È possibile salvare un byte rimuovendo =alla fine della definizione di Oe modificare lo spazio che segue ogni chiamata Oin a =.
Zacharý,

Questo è fantastico;) A proposito della "limitazione", vedi anche il mio commento sulla domanda stessa - rilevare questo aggiungerebbe troppa complessità.
Felix Palmen,

@Zachary - grazie per quello - Ho dimenticato quando ho cambiato il codice generale in ASCII specifico O'\\'ed O' 'entrambi hanno acquisito uno spazio.
Toby Speight,


2

C,  705   663  640 byte

Grazie a @ Zacharý per giocare a golf 40 byte e grazie a @Nahuel Fouilleul per giocare a 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;}

Provalo online!


Può for(;W;C++){}diventare for(;W;C++);?
Zacharý,

@ Zacharý che non è mai stato chiesto. È un trucco per l'ultimo passo: rimuovere spazi bianchi e commenti ridondanti.
Felix Palmen,

Mi riferivo al suo codice, non alla sfida.
Zacharý,

@ Zacharý haha ​​Vedo ... strano quando il codice e l'input sono nella stessa lingua;)
Felix Palmen,

Funzionerebbe con 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/./

Provalo online


Sì, ho appena messo una soluzione non ottimale. Ho appena aggiunto il link tio, cercherò di giocare a golf quando avrò tempo.
Nahuel Fouilleul,

la direttiva del preprocessore è sulla propria riga quando viene posizionata prima del codice, come nei casi di test, tuttavia, se è necessario, aggiungerò il cambiamento
Nahuel Fouilleul,

1
risolto vedi aggiornamento
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'++ -- /*']

Provalo online!

Edit: Fisso per includere - -, + +e/ *

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.