Гольф мій "попередньо гольф" C


12

Фон

Для мого подання в C мені потрібен інструмент для обробки. Як і в багатьох інших мовах, пробіл в основному не має значення в джерелі С (але не завжди!) - все ще робить код набагато зрозумілішим для людини. Повністю гольф програма C, яка не містить жодного зайвого пробілу, часто ледве читається.

Тому я люблю писати свій код на C для подання включаючи пробіли та інколи коментарі, тому програма зберігає зрозумілу структуру під час написання. Останній крок - видалити всі коментарі та зайвий пробіл. Це виснажлива і безглузда задача, яку справді повинен робити стажист за допомогою комп’ютерної програми.

Завдання

Напишіть програму або функцію, яка виключає коментарі та зайві пробіли з якогось джерела С "за попереднього гольфу" відповідно до таких правил:

  • A \(зворотна косою рисою) як останній символ у рядку є продовженням рядка . Якщо ви виявите це, ви повинні розглядати наступний рядок як частину одного логічного рядка (ви можете, наприклад, повністю видалити \та наступний \n(новий рядок), перш ніж робити щось інше)
  • Коментарі будуть використовувати лише однорядковий формат, починаючи з //. Отже, щоб видалити їх, ви ігноруєте решту логічного рядка, де б ви не стикалися //поза рядковим літералом (див. Нижче).
  • Символи пробілів - це (пробіл), \t(вкладка) та \n(новий рядок, тому тут кінець логічного рядка).
  • Коли ви знайдете послідовність пробілів, вивчіть символи, що не містять пробілів, що їх оточують. Якщо

    • обидва вони буквено-цифрові або підкреслення (діапазон [a-zA-Z0-9_]) або
    • обидва є +або
    • обидва є -або
    • попередній є, /а наступний -*

    потім замініть послідовність одним символом пробілу ( ).

    В іншому випадку усуньте послідовність повністю.

    Це правило має деякі винятки :

    • Попередні директиви повинні відображатись у власних рядках у вашому висновку. Директива щодо препроцесора - це рядок, що починається з #.
    • Всередині рядкового літералу чи літералу символів не слід видаляти пробіли. Будь-яка "(подвійна цитата) / '(одноцитата), яка безпосередньо не передує непарною косою косою рисою ( \), починає або закінчує рядковий літерал / буквений символ . Вам гарантовано, що літеральні рядки та символи закінчуються в тому ж рядку, що вони почали. Строкові літерали та літерали символів не можуть бути вкладеними, тому 'всередині рядкового літералу , а також "усередині літерального символу немає особливого значення.

Специфікація вводу / виводу

Введення та вихід мають бути або послідовностями символів (рядками), включаючи символи нового рядка, або масиви / списки рядків, які не містять символів нового рядка. Якщо ви вирішите використовувати масиви / списки, кожен елемент являє собою рядок, тому нові рядки є неявними після кожного елемента.

Ви можете припустити, що вхід - це дійсний вихідний код програми C. Це також означає, що він містить лише символи, вкладки та нові рядки для друку ASCII. Допускається не визначена поведінка на неправильному введенні.

Ведучі й відомі прогалини / порожні рядки є не допускаються .

Тестові справи

  1. вхід

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

    вихід

    main(){printf("Hello, World!");}
    
  2. вхід

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

    вихід

    #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. вхід

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

    вихід

    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. вхід

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

    вихід

    x;
    #include<stdio.h>
    int main(){puts("hello // there");}
    
  5. вхід (реальний приклад)

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

    вихід

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

Це , тому виграє найкоротша (у байтах) справжня відповідь.



Відповіді:


4

Піп , 148 135 133 138 байт

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

Байти підраховуються в CP -1252 , так і ·в один байт кожен. Зауважте, що це очікує, що код C є єдиним аргументом командного рядка, який (у фактичному командному рядку) вимагатиме використання рясних послідовностей евакуації. Спробувати це онлайн набагато простіше !

Пояснення злегка неперевершеної версії

Код виконує купу операцій із заміни, з кількома хитрощами.

Продовження зворотного косу

Ми RMвсі випадки буквеного рядка

"\
"

тобто зворотний нахил з наступним рядком.

Літеральні рядки та символи

Ми використовуємо регекс-заміну з функцією зворотного виклику:

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

{
 lPBa
 C(++i + 191)
}

Регекс відповідає одній або подвійній цитаті, а за нею - жадібний, .*?який відповідає 0 і більше символів, як можна менше. Ми маємо негативний погляд на те, щоб попередній персонаж не був зворотним косою рисою; то ми підбираємо рівну кількість зворотних косих ринків, після чого знову відкривається роздільник.

Функція зворотного виклику приймає буквальний рядок / символ і натискає його на зворотній бік списку l. Потім він повертає символ, починаючи з коду символу 192 ( À) і збільшуючись із кожною заміненою буквальною формою. Таким чином, код трансформується так:

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

printf(À, Á);

Гарантовано, що ці символи заміни не з'являться у вихідному коді, а значить, ми можемо однозначно їх замінити пізніше.

Коментарі

`//.*`

x

Регекс збігається //з усім, що відповідає новому рядку, і заміняється на x(попередньо заданий порожній рядок).

Допроцесорні директиви

`#.*`

_WR'¶

Обгортання запущених символів, що не входять у новий рядок, починаючи з входу в фунт .

Проміжки, які не повинні бути усунені

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

{
 a R w '·
}

Тут багато чого відбувається. Перша частина генерує цей список регулярних виразів для заміни:

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

Зверніть увагу на використання lookaheads для відповідності, наприклад, тільки e в define P printf. Таким чином цей збіг не споживає P, а значить, наступний матч може використовувати його.

Ми генеруємо цей список регексів, зіставляючи функцію зі списком, де список міститься

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

і функція робить це для кожного елемента:

(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

Після того, як у нас з'являються наші реджекси, ми замінюємо їх виникнення на цю функцію зворотного виклику:

{aRw'·}

який замінює пробіл пробілів у кожному матчі з ·.

Видалення та очищення пробілу

[w `¶+` '·]

[x n s]

Три послідовні заміни заміщають залишки пробілів ( w) для порожнього рядка ( x), пробілів для нового рядка та ·пробілу.

Зворотна підміна літеральних рядків і символів

C(192+,#l)

l

Ми будуємо список усіх символів, які ми використовували в якості заміни літералів, приймаючи 192 + range(len(l))та перетворюючи на символи. Тоді ми можемо замінити кожну з них на відповідну літералу в l.

І це все! Отриманий рядок є автодрукованим.


Чудово, я вражений (+1)! Включення //всередину рядкового літералу, безумовно, є хорошою ідеєю для тестового випадку, я додам його завтра.
Фелікс Палмен

Гм ... зараз я тут також знайшов тонку помилку ...
Фелікс Палмен

Я виберу переможця через 14 днів (кінець наступного тижня), і ваше рішення стане першим кандидатом, якщо ви знайдете час виправити цю помилку. Зараз у вас найнижчий результат :)
Фелікс Палмен

1
@FelixPalmen Виправлено!
DLosc

7

Haskell , 327 360 418 394 байт

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

Спробуйте в Інтернеті!

Це було дуже весело писати! Спочатку fфункція проходить через і видаляє всі зворотні риски в кінці рядків, потім linesрозбиває її на список рядків у нових рядках. Тоді ми накреслюємо купу функцій на лінії і з'єднуємо їх усі разом. Ці функції: смуга пробілу зліва ( t) і справа ( r.t.rде rє reverse); видаліть пробіл з середини, ігноруючи рядки рядків та символів, а також видаляючи коментарі ( w); і, нарешті, додає символ нового рядка до кінця, якщо рядок починається з #. Після об'єднання всіх рядків разом gшукає # символів і гарантує, що їм передує новий рядок.

wтрохи складний, тому я поясню це далі. Спочатку я перевіряю "//", оскільки в wкурсі я знаю, що я не в прямому рядку, я знаю, що це коментар, тому я кидаю решту рядка. Далі я перевіряю, чи заголовок є роздільником для рядка чи буквеного символу. Якщо це так, я додаю його і передаю естафету, до lякої пробігаються персонажі, відстежуючи стан "втечі", з nяким буде істинно, якщо було парне число послідовних косих рядків. При lвиявленні роздільник і не в змозі втечі він передає естафету назад до w, обрізку усунути пробілу після литерала , оскільки wочікує , що перший символ НЕ може бути пробіл. Колиwне знайде роздільника, він використовує проліт, щоб шукати пробіли в хвості. Якщо він є, він перевіряє, чи не можуть символи навколо нього приводитись у контакт і вставляє пробіл, якщо так. Потім він повторюється після закінчення пробілу. Якщо пробілу не було, не вставляється пробіл і він все одно рухається.

EDIT: Дякую @DLosc за вказівку на помилку в моїй програмі, що фактично призвело до того, що я також міг скоротити її! Ураг для узгодження моделей!

EDIT2: Я ідіот, який не закінчив читати специфікацію! Ще раз дякую DLosc за вказівку на це!

EDIT3: Просто помітив деякі дратівливі скорочення типу річ , яка перетворилася e=elemв Char->[Char]->Boolз якої - то причини, що порушення на e[a,q]. Мені довелося додати підпис типу, щоб змусити його бути правильним. Хтось знає, як я можу це виправити? Я ніколи раніше не мав цієї проблеми в Хаскеллі. ТІО

EDIT4: швидко виправити помилку @FelixPalmen показав мені. Я можу спробувати пограти в гольф пізніше, коли у мене буде час.

EDIT5: -24 байти завдяки @Lynn! Дякую! Я не знав, що ви можете призначити речі в глобальному масштабі, використовуючи відповідність шаблонів, як n:c:z=...це дійсно круто! Також гарна ідея зробити оператора за elemбажанням, я про це подумав.



2
Ви стикаєтеся з жахливим обмеженням мономорфізму ; визначення e x y=elem x y(або навіть e x=elem x) вирішує вашу проблему. (Я перейменований eна оператора (!).)
Лінн

3

C, 497 494 490 489 байт

Оскільки ми обробляємо C, давайте зробимо це за допомогою C! Функція f()приймає вхід з покажчика char pі виводить на покажчик q, і передбачає, що вхід знаходиться в 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)();}

Ми припускаємо, що файл добре сформований - літеральні рядки та символи закриті, і якщо є коментар до остаточного рядка, для його закриття повинен бути новий рядок.

Пояснення

Боюся, попередньо гольф-версія лише трохи розбірливіша:

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

Він реалізує стан машини за допомогою хвостової рекурсії. Допоміжні макроси та змінні є

  • Oдля o utput
  • Rщоб R EAD введення вr
  • Vдля визначення символів v ідентифікатора alid (з моменту !isalnum('_'))
  • pі q- вказівники вводу / виводу, як описано
  • r- останній персонаж, який буде r ead
  • s- s aved нещодавнього непробільного символу
  • t- t ag при роботі над директивою про препроцесор

Наші держави є

  • a() - звичайний код C
  • b() - рядковий буквальний
  • c() - коментар
  • d() - звичайний код C, після прочитання r
  • e() - послідовність втечі
  • f() - початковий стан (основна функція)
  • g() - у пробілі
  • h()- у пробілі - відправлення до g()абоi()
  • i() - відразу після пробілів - нам потрібно вставити пробіл?
  • j() - початковий пробіл - ніколи не вставляйте пробіл

Тестова програма

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

Це виробляє

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

Обмеження

Це порушує такі визначення, як

#define A (x)

шляхом вилучення простору, що відокремлює ім’я від розширення, надання

#define A(x)

з зовсім іншим значенням. Цей випадок відсутній у тестових наборах, тому я не збираюся його вирішувати.

Я підозрюю, що мені вдасться створити скорочену версію з багатопрохідним перетворенням на місце - я можу спробувати це на наступному тижні.


Ви можете зберегти один байт, видаливши =в кінці визначення Oта змінивши пробіл, який слідує за кожним викликом, Oна a =.
Zacharý

Це чудово;) Щодо "обмеження", дивіться також мій коментар до самого питання - виявлення цього додало б занадто великої складності.
Фелікс Палмен

@Zachary - дякую за це - я забув, коли змінив загальний код на специфічний для ASCII, що O'\\'і O' 'обидва придбав пробіл.
Toby Speight


2

C,  705   663  640 байт

Дякуємо @ Zacharý за гольф на 40 байт та дякуємо @Nahuel Fouilleul за теніс на гольфі 23 байти!

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

Спробуйте в Інтернеті!


Може for(;W;C++){}стати for(;W;C++);?
Zacharý

@ Zacharý, про яку ніколи не просили. Це занадто велика кількість останнього кроку: видаліть зайві пробіли та коментарі.
Фелікс Палмен

Я мав на увазі його код, а не виклик.
Zacharý

@ Zacharý haha ​​Я бачу ... дивно, коли код і введення однакові;)
Фелікс Палмен

Це працювало б на 665 байт? goo.gl/E6tk8V
Zacharý

2

Perl 5, 250 + 3 (-00n) , 167 + 1 (-p) байт

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

Спробуйте в Інтернеті


Так, я просто поставив неоптимальне рішення. Я тільки що додав посилання на tio, я буду дивитись, щоб пограти в нього, коли встигну.
Nahuel Fouilleul

Директива препроцесора знаходиться в їхньому власному рядку, коли їх розміщують перед кодом, як і в тестових випадках, проте, якщо цього потрібно, я
додаду

1
виправлено див. оновлення
Nahuel Fouilleul

0

Python 2 , 479 456 445 434 502 497 байт

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

Спробуйте в Інтернеті!

Edit: Фіксований включити - -, + +і/ *

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.