Golf mon «pré-golf» C

12

Contexte

Pour mes soumissions de en C, j'ai besoin d'un outil de traitement. Comme dans de nombreux autres langages, les espaces blancs ne sont généralement pas pertinents dans la source C (mais pas toujours!) - rendent le code beaucoup plus compréhensible pour les humains. Un programme C entièrement joué qui ne contient pas un seul espace redondant est souvent à peine lisible.

Par conséquent, j'aime écrire mon code en C pour une soumission de comprenant des espaces et parfois des commentaires, afin que le programme conserve une structure compréhensible lors de l'écriture. La dernière étape consiste à supprimer tous les commentaires et les espaces blancs redondants. C'est une tâche fastidieuse et insensée qui devrait vraiment être effectuée par un stagiaire dans un programme informatique.

Tâche

Écrivez un programme ou une fonction qui élimine les commentaires et les espaces blancs redondants d'une source C "pré-golfée" selon les règles suivantes:

  • Un \(barre oblique inversée) comme dernier caractère d'une ligne est une continuation de ligne . Si vous trouvez cela, vous devez traiter la ligne suivante comme faisant partie de la même ligne logique (vous pouvez par exemple supprimer complètement le \et le suivant \n(nouvelle ligne) avant de faire quoi que ce soit d'autre)
  • Les commentaires utiliseront uniquement le format d'une ligne, en commençant par //. Donc, pour les supprimer, vous ignorez le reste de la ligne logique partout où vous rencontrez en //dehors d'un littéral de chaîne (voir ci-dessous).
  • Les caractères d' espacement sont (espace), \t(tabulation) et \n(nouvelle ligne, donc voici la fin d'une ligne logique).
  • Lorsque vous trouvez une séquence d'espaces blancs, examinez les caractères non blancs qui l'entourent. Si

    • les deux sont alphanumériques ou soulignés (plage [a-zA-Z0-9_]) ou
    • les deux sont +ou
    • les deux sont -ou
    • celui qui précède est /et le suivant est*

    puis remplacez la séquence par un seul caractère espace ( ).

    Sinon, supprimez complètement la séquence.

    Cette règle comporte quelques exceptions :

    • Les directives du préprocesseur doivent apparaître sur leurs propres lignes dans votre sortie. Une directive de préprocesseur est une ligne commençant par #.
    • À l'intérieur d'un littéral de chaîne ou d' un littéral de caractère , vous ne devez supprimer aucun espace. Tout "(guillemet double) / '(guillemet simple) qui n'est pas directement précédé d'un nombre impair de barres obliques inverses ( \) démarre ou termine un littéral de chaîne / un littéral de caractère . Vous êtes assuré que les littéraux de chaîne et de caractère se terminent sur la même ligne qu'ils ont commencée. les littéraux de chaîne et les littéraux de caractère ne peuvent pas être imbriqués, donc l' 'intérieur d'un littéral de chaîne , ainsi que l' "intérieur d'un littéral de caractère n'ont pas de signification particulière.

Spécifications d'E / S

L'entrée et la sortie doivent être soit des séquences de caractères (chaînes), y compris des caractères de nouvelle ligne, soit des tableaux / listes de chaînes qui ne contiennent pas de caractères de nouvelle ligne. Si vous choisissez d'utiliser des tableaux / listes, chaque élément représente une ligne, donc les sauts de ligne sont implicites après chaque élément.

Vous pouvez supposer que l'entrée est un code source de programme C valide. Cela signifie également qu'il ne contient que des caractères ASCII imprimables, des tabulations et des retours à la ligne. Un comportement non défini sur une entrée mal formée est autorisé.

Les espaces vides de début et de fin ne sont pas autorisés .

Cas de test

  1. contribution

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

    production

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

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

    production

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

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

    production

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

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

    production

    x;
    #include<stdio.h>
    int main(){puts("hello // there");}
    
  5. entrée (un exemple du monde réel)

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

    production

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

C'est le , donc la réponse valide la plus courte (en octets) l'emporte.

Felix Palmen
la source
liés , liés
HyperNeutrino
Continuons cette discussion dans le chat .
DLosc

Réponses:

4

Pip , 148 135 133 138 138 octets

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

Les octets sont comptés dans CP-1252 , donc et ·sont un octet chacun. Notez que cela attend le code C comme un argument de ligne de commande unique, qui (sur une ligne de commande réelle) nécessiterait l'utilisation de séquences d'échappement copieuses. C'est beaucoup plus simple sur Essayez-le en ligne!

Explication de la version légèrement non golfée

Le code effectue un tas d'opérations de remplacement, avec quelques astuces.

Poursuite de la barre oblique inverse

Nous avons RMtous les occurrences de la chaîne littérale

"\
"

c'est-à-dire une barre oblique inverse suivie d'une nouvelle ligne.

Littéraux de chaîne et de caractère

Nous utilisons un remplacement d'expression régulière avec une fonction de rappel:

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

{
 lPBa
 C(++i + 191)
}

L'expression régulière correspond à une citation simple ou double, suivie d'une non gourmande .*?qui correspond à 0 ou plusieurs caractères, le moins possible. Nous avons un lookbehind négatif pour nous assurer que le personnage précédent n'était pas une barre oblique inverse; nous faisons alors correspondre un nombre pair de barres obliques inverses, suivi à nouveau du délimiteur d'ouverture.

La fonction de rappel prend le littéral chaîne / caractère et le pousse à l'arrière de la liste l. Il retourne ensuite un caractère commençant par le code de caractère 192 ( À) et augmentant avec chaque littéral remplacé. Ainsi, le code est transformé comme suit:

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

printf(À, Á);

Ces caractères de remplacement sont garantis de ne pas apparaître dans le code source, ce qui signifie que nous pouvons les remplacer sans ambiguïté ultérieurement.

commentaires

`//.*`

x

Le regex correspond à //plus tout jusqu'à la nouvelle ligne et remplace par x(prédéfini sur la chaîne vide).

Directives du préprocesseur

`#.*`

_WR'¶

Encapsule des séries de caractères non-newline commençant par une connexion dièse .

Espaces à ne pas supprimer

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

{
 a R w '·
}

Il se passe beaucoup de choses ici. La première partie génère cette liste de regex à remplacer:

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

Notez l'utilisation de lookaheads pour faire correspondre, par exemple, juste le e in define P printf. De cette façon, cette correspondance ne consomme pas le P, ce qui signifie que la correspondance suivante peut l'utiliser.

Nous générons cette liste d'expressions régulières en mappant une fonction à une liste, où la liste contient

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

et la fonction fait cela pour chaque élément:

(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

Une fois que nous avons nos expressions régulières, nous remplaçons leurs occurrences par cette fonction de rappel:

{aRw'·}

qui remplace la série d'espaces dans chaque match avec ·.

Élimination et nettoyage des espaces blancs

[w `¶+` '·]

[x n s]

Trois remplacements successifs remplacent les wséquences restantes de blanc ( ) par la chaîne vide ( x), les séquences de pour la nouvelle ligne et l' ·espace.

Substitution de substitution des littéraux de chaîne et de caractère

C(192+,#l)

l

Nous construisons une liste de tous les caractères que nous avons utilisés comme substitutions aux littéraux en prenant 192 + range(len(l))et en convertissant en caractères. Nous pouvons alors remplacer chacun d'eux par son littéral associé dans l.

Et c'est tout! La chaîne résultante est imprimée automatiquement.

DLosc
la source
Génial, je suis impressionné (+1)! Inclure un //littéral de chaîne à l'intérieur est certainement une bonne idée pour un cas de test, j'en ajouterai un demain.
Felix Palmen
Uhm ... maintenant j'ai trouvé un bug subtil ici aussi ...
Felix Palmen
Je vais choisir un gagnant après 14 jours (fin de la semaine prochaine) et votre solution serait le premier candidat si vous trouvez le temps de corriger ce bug. En ce moment, vous avez le score le plus bas :)
Felix Palmen
1
@FelixPalmen Fixed!
DLosc
7

Haskell , 327 360 418 394 octets

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

Essayez-le en ligne!

C'était très amusant à écrire! Tout d'abord, la ffonction apparaît et supprime toutes les barres obliques inverses à la fin des lignes, puis la linesdécompose en une liste de chaînes aux nouvelles lignes. Ensuite, nous mappons un tas de fonctions sur les lignes et les concaténons toutes ensemble. Ces fonctions: supprimer les espaces blancs de gauche ( t) et de droite ( r.t.rrest reverse); supprimer les espaces du milieu, en ignorant les littéraux de chaîne et de caractères ainsi que la suppression des commentaires ( w); et ajoute enfin un caractère de nouvelle ligne à la fin si la ligne commence par un #. Une fois que toutes les lignes sont concaténées, elles grecherchent # caractères et s'assurent qu'elles sont précédées d'une nouvelle ligne.

west un peu complexe, je vais donc l'expliquer davantage. Je vérifie d'abord "//" car wje sais que je ne suis pas dans une chaîne littérale, je sais que c'est un commentaire, donc je laisse tomber le reste de la ligne. Ensuite, je vérifie si la tête est un délimiteur pour une chaîne ou un littéral de caractère. Si c'est le cas, je le fais précéder et je passe le témoin vers llequel parcourent les personnages, en suivant l'état "d'échappement" avec nlequel il sera vrai s'il y a eu un nombre pair de barres obliques consécutives. Lorsqu'il ldétecte un délimiteur et n'est pas dans l'état d'échappement, il passe le relais à w, le découpage pour éliminer les espaces après le littéral, car il ws'attend à ce que le premier caractère ne soit pas un espace. Quandwne trouve pas de délimiteur, il utilise span pour rechercher des espaces dans la queue. S'il y en a, il vérifie si les personnages qui l'entourent ne peuvent pas être mis en contact et insère un espace si c'est le cas. Il se reproduit ensuite une fois l'espace vide terminé. S'il n'y avait pas d'espace, aucun espace n'est inséré et il continue quand même.

EDIT: Merci beaucoup à @DLosc pour avoir signalé un bogue dans mon programme qui m'a également permis de le raccourcir! Hourra pour la correspondance des motifs!

EDIT2: Je suis un idiot qui n'a pas fini de lire la spécification! Merci encore DLosc de l'avoir signalé!

EDIT3: Je viens de remarquer une chose de réduction de type ennuyeuse qui s'est e=elemtransformée Char->[Char]->Boolpour une raison quelconque, se brisant ainsi e[a,q]. J'ai dû ajouter une signature de type pour la forcer à être correcte. Est-ce que quelqu'un sait comment je pourrais résoudre ce problème? Je n'ai jamais eu ce problème à Haskell auparavant. TIO

EDIT4: correction rapide du bug @FelixPalmen m'a montré. Je pourrais essayer de jouer au golf plus tard quand j'aurai du temps.

EDIT5: -24 octets grâce à @Lynn! Je vous remercie! Je ne savais pas que vous pouviez attribuer des choses sur la portée globale en utilisant la correspondance de motifs comme n:c:z=...si c'était vraiment cool! Aussi une bonne idée de faire un opérateur pour le elemsouhait que j'y avais pensé.

user1472751
la source
1
J'ai pressé 24 octets .
Lynn
2
Vous rencontrez la restriction redoutée du monomorphisme ; définir e x y=elem x y(ou même e x=elem x) résout votre problème. (J'ai renommé eun opérateur,. (!))
Lynn
3

C, 497 494 490 489 octets

Puisque nous traitons C, faisons-le en utilisant C! La fonction f()prend l'entrée du pointeur char pet les sorties vers le pointeur q, et suppose que l'entrée est en 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)();}

Nous supposons que le fichier est bien formé - les littéraux de chaîne et de caractère sont fermés, et s'il y a un commentaire sur la dernière ligne, il doit y avoir une nouvelle ligne pour la fermer.

Explication

La version pré-golfée n'est que légèrement plus lisible, je le crains:

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

Il implémente une machine à états par récursivité de queue. Les macros et variables d'aide sont

  • Opour o utput
  • Rà r l'entrée de enr
  • Vpour déterminer v caractères d'identificateur alides (depuis !isalnum('_'))
  • pet q- pointeurs d'E / S comme décrit
  • r- dernier caractère à r ead
  • s- s Aved récent caractère non-blanc
  • t- t ag lorsque vous travaillez sur une directive de préprocesseur

Nos états sont

  • a() - code C normal
  • b() - chaîne littérale
  • c() - commenter
  • d() - code C normal, après lecture r
  • e() - séquence d'échappement
  • f() - état initial (fonction principale)
  • g() - en blanc
  • h()- en blanc - envoi vers g()oui()
  • i() - immédiatement après un espace - devons-nous insérer un caractère espace?
  • j() - espace initial - ne jamais insérer de caractère espace

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

Cela produit

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

Limitation

Cela rompt les définitions telles que

#define A (x)

en supprimant l'espace qui sépare le nom de l'expansion, donnant

#define A(x)

avec un sens entièrement différent. Ce cas est absent des ensembles de tests, donc je ne vais pas y remédier.

Je soupçonne que je pourrais être en mesure de produire une version plus courte avec une conversion sur place multi-passes - je pourrais essayer la semaine prochaine.

Toby Speight
la source
Vous pouvez enregistrer un octet en supprimant le =à la fin de la définition de Oet changer l'espace qui suit chaque appel en Oen =.
Zacharý
C'est grand;) A propos de la « limitation », voir aussi mon commentaire sur la question elle - même - la détection de ce ajouterait trop de complexité.
Felix Palmen du
@Zachary - merci pour cela - j'ai oublié quand j'ai changé le code général en ASCII spécifique O'\\'et que les O' 'deux ont acquis un espace.
Toby Speight
464 octets
plafond du
2

C,  705   663  640 octets

Merci à @ Zacharý pour avoir joué au golf 40 octets et merci à @Nahuel Fouilleul pour avoir joué au golf 23 octets!

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

Essayez-le en ligne!

Steadybox
la source
Peut for(;W;C++){}devenir for(;W;C++);?
Zacharý
@ Zacharý qui n'a jamais été demandé. C'est un outil pour la toute dernière étape: supprimer les espaces et les commentaires redondants.
Felix Palmen du
Je faisais référence à son code, pas au défi.
Zacharý
@ Zacharý haha ​​je vois ... bizarre quand le code et la saisie sont la même langue;)
Felix Palmen
Est-ce que cela fonctionnerait pour 665 octets? goo.gl/E6tk8V
Zacharý
2

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

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

Essayez-le en ligne

Nahuel Fouilleul
la source
Oui, je viens de mettre une solution non optimale. Je viens d'ajouter le lien tio, je regarderai le golf quand j'aurai le temps.
Nahuel Fouilleul
les directives du préprocesseur sont sur leur propre ligne quand elles sont placées avant le code, comme dans les cas de test cependant si c'est nécessaire j'ajouterai le changement
Nahuel Fouilleul
1
corrigé voir la mise à jour
Nahuel Fouilleul
0

Python 2 , 479 456 445 434 502 497 octets

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'++ -- /*']

Essayez-le en ligne!

Edit: Correction d'inclure - -, + +et/ *

TFeld
la source