Прочитайте декларацію змінної C


41

Фон

Заява змінної декларації в C складається з трьох частин: назва змінної, її базовий тип та модифікатор (и) типу .

Існує три види модифікаторів типу:

  • Вказівник *(префікс)
  • Масив [N](постфікс)
  • Функція ()(постфікс)
    • Ви можете вказати список аргументів функції всередині паролів, але заради цього виклику давайте ігноруємо його та просто використовуємо ()(що технічно означає "функція може приймати будь-які аргументи").

А спосіб прочитати нотації такий:

int i;             // i is an int
float *f;          // f is a pointer to a float
my_struct_t s[10]; // s is an array of 10 my_struct_t
int func();        // func is a function returning an int

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

int arr[3][4];
// arr is an array of 3 arrays of 4 ints

int (*fptrs[10])();
// fptrs is an array of 10 pointers to functions returning an int

float *(*p)[16];
// p is a pointer to an array of 16 pointers to float

Як я прочитав ці складні заяви?

  1. Почніть з назви змінної. (name) is ...
  2. Виберіть модифікатор з найвищим пріоритетом.
  3. Читати:
    • * -> pointer to ...
    • [N] -> array of N ...
    • () -> function returning ...
  4. Повторюйте 2 і 3, поки модифікатори не вичерпані.
  5. Нарешті, прочитайте базовий тип. ... (base type).

У C оператори Postfix мають перевагу над префіксними операторами, і модифікатори типу не є винятком. Тому []і ()зв’яжіть спочатку, потім *. Все, що знаходиться всередині пари паронів (...)(не плутати з оператором функції), пов'язує спочатку над чим-небудь зовнішнім.

Ілюстрований приклад:

int (*fptrs[10])();
      fptrs           fptrs is ...
           [10]       array of 10 ... // [] takes precedence over *
    (*         )      pointer to ...
                ()    function returning ...
int                   int

Завдання

З огляду на рядок заяви заяви про змінну, записану на C, виведіть англійський вираз, який описує рядок, використовуючи метод, показаний вище.

Вхідні дані

Вхід - це єдине твердження C, яке включає єдиний базовий тип, одне ім'я змінної, модифікатори нуля або більше типів і кінцеву крапку з комою. Ви повинні реалізувати всі елементи синтаксису, описані вище, плюс:

  • І базовий тип, і назва змінної відповідають регулярному виразу [A-Za-z_][A-Za-z0-9_]*.
  • Теоретично ваша програма повинна підтримувати необмежену кількість модифікаторів типів.

Ви можете спростити інші елементи синтаксису С наступними способами (також можлива повна реалізація):

  • Базовий тип завжди одне слово, наприклад int, float, uint32_t, myStruct. Щось подібне unsigned long longне буде перевірено.
  • Для позначення масиву [N], число Nзавжди буде одне ціле позитивне число записується в базі 10. Такі речі , як int a[5+5], int a[SIZE]або int a[0x0f]НЕ будуть перевірені.
  • Для позначення функції (), параметри взагалі не будуть вказані, як зазначено вище.
  • Для пробілів 0x20буде використовуватися лише пробіл . Ви можете обмежити свою програму конкретним використанням пробілів, наприклад
    • Використовуйте лише один пробіл після базового типу
    • Використовуйте пробіл скрізь між маркерами
  • Однак ви не можете використовувати два чи більше послідовних пробілів, щоб передати більше інформації, ніж бути роздільником токенів.

Відповідно до синтаксису C, наступні три комбінації є недійсними, тому вони не будуть перевірені:

  • f()() Функція повернення функції
  • f()[] Функція повертає масив
  • a[]() Масив N функцій

Розробники C натомість використовують ці еквівалентні форми (і всі вони охоплені у тестових випадках):

  • (*f())()Функція повертає вказівник на функцію
  • *f()Функція, що повертає вказівник на перший елемент масиву
  • (*a[])()Для функціонування масив N покажчиків

Вихідні дані

Вихід - єдине англійське речення. Вам не потрібно (але ви можете, якщо хочете) поважати граматику англійської мови, наприклад, використання форм a, an, theоднини / множини та закінчувальну крапку (період). Кожне слово має бути розділене одним або декількома пробілами (пробіл, вкладка, новий рядок), щоб результат був зрозумілий людині.

Знову ось процес перетворення:

  1. Почніть з назви змінної. (name) is ...
  2. Виберіть модифікатор з найвищим пріоритетом.
  3. Читати:
    • * -> pointer to ...
    • [N] -> array of N ...
    • () -> function returning ...
  4. Повторюйте 2 і 3, поки модифікатори не вичерпані.
  5. Нарешті, прочитайте базовий тип. ... (base type).

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

int i;              // i is int
float *f;           // f is pointer to float
my_struct_t s[10];  // s is array of 10 my_struct_t
int func();         // func is function returning int
int arr[3][4];      // arr is array of 3 array of 4 int
int (*fptrs[10])(); // fptrs is array of 10 pointer to function returning int
float *(*p)[16];    // p is pointer to array of 16 pointer to float

_RANdom_TYPE_123 (**(*_WTH_is_TH15)())[1234][567];
/* _WTH_is_TH15 is pointer to function returning pointer to pointer to array of
   1234 array of 567 _RANdom_TYPE_123 */

uint32_t **(*(**(*(***p)[2])())[123])[4][5];
/* p is pointer to pointer to pointer to array of 2 pointer to function returning
   pointer to pointer to array of 123 pointer to array of 4 array of 5 pointer to
   pointer to uint32_t */

uint32_t (**((*(**(((*(((**(*p)))[2]))())))[123])[4])[5]);
// Same as above, just more redundant parens

some_type (*(*(*(*(*curried_func())())())())())();
/* curried_func is function returning pointer to function returning pointer to
   function returning pointer to function returning pointer to
   function returning pointer to function returning some_type */

Критерій оцінювання та виграшу

Це проблема з . Виграє програма з найменшою кількістю байтів.


9
Пов'язано: cdecl.org
користувач202729

int arr[3][4];є an array of 3 arrays of 4 ints(як ви кажете), або an array of 4 arrays of 3 ints?
Чарлі

1
@Charlie Колишній правильний. sizeof(arr[0]) == sizeof(int[4]), тому елемент arrмістить чотири intс.
Бубон

1
Чи містить дані ;в кінці рядка?
Чорна сова Кай

2
@KamilDrakari Це останнє. "масив вказівника на функцію" є по суті "масивом вказівника", що цілком справедливо в C.
Bubbler

Відповіді:


17

Python 3 , 331 312 294 261 240 байт

from re import*
class V(str):__pos__=lambda s:V(s+'pointer to ');__call__=lambda s:V(s+'function returning ');__getitem__=lambda s,i:V(s+'array of %i '%i)
t,e=input().split()
print(eval(sub('\*','+',sub('(\w+)',r'V("\1 is ")',e[:-1],1)))+t)

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

-19 байт шляхом переходу на python 2 та введення визначення класу в exec

-18 байт, змінивши регулярний вираз від [a-zA-Z_][a-zA-Z0-9_]*до \\w+, завдяки Kevin Cruijssen

-33 байти, працюючи з деякими магіями визначення класу та використовуючи str, завдяки Лінн повертається до python 3

-21 байт, об'єднавши разом декілька регулярних виразів, завдяки infmagic2047

Потрібно, щоб у вході містився лише один пробіл (між типом і виразом).

Я думаю, що це досить унікальний підхід до проблеми. В основному це використовує той факт, що Python сам може оцінювати рядки, як (**((*(**(((*(((**(*p)))[2]))())))[123])[4])[5])і отримує правильну послідовність викликів функцій, індексів масиву та покажчиків - і що користувач може їх перевантажувати.


1
Гарний підхід, +1 від мене! Ви можете в гольф, [a-zA-Z_][A-Za-z0-9_]*щоб [a-zA-Z_]\\w*зберегти кілька байт. EDIT: Насправді, я думаю, ви можете просто використовувати \\w+замість цього [a-zA-Z_][A-Za-z0-9_]*.
Kevin Cruijssen

Мені подобається такий підхід :) ось він у 253 байтах
Лінн

1
Це хороший момент. 261 це тоді.
Лінн

1
Ви можете використовувати [0]замість .group()Python 3.6.
infmagic2047


13

Сітківка 0.8.2 , 142 138 128 117 байт

(\w+) (.+);
($2) $1
\(\)
 function returning
\[(\d+)?]
 array of$#1$* $1
+`\((\**)(.+)\)
$2$1
\*
 pointer to
1` 
 is 

Спробуйте в Інтернеті! Посилання включає тестові випадки. Краще граматики . Редагувати: Збережено 10 21 байт за допомогою перенесення рішення Pip @ DLosc. Пояснення:

(\w+) (.+);
($2) $1

Перемістіть тип до кінця і загорніть решту декларації в ()s, якщо вона містить зовнішню *.

\(\)
 function returning

Обробляйте будь-які функції.

\[(\d+)?]
 array of$#1$* $1

Обробляти будь-які масиви.

+`\((\**)(.+)\)
$2$1

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

\*
 pointer to

Обробляйте будь-які вказівники.

1` 
 is 

Вставте is.


7

Java 11, 469 467 463 450 байт

s->{String r="",t,S[];for(s=s.replace("()","~");s.contains("(");s=s.replace(t,"").replace("()",""),r+=t+";")t=s.replaceAll(".*(\\([^()]+\\)).*","$1");S=s.split(" ");t=S[0];r+=r.isEmpty()?S[1]:s;S=r.split(";");r=S[0].replaceAll(".*?(\\w+).*","$1 is ");for(var p:S)r+=p.replaceAll("[A-Za-z_]+\\d+|[^\\[\\d]","").replaceAll("\\[(\\d+)","array of $1 ")+(p.contains("~")?"function returning ":"")+"pointer to ".repeat(p.split("\\*").length-1);return r+t;}

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

Пояснення:

s->{               // Method with String as both parameter and return-type
  String r="",     //  Result-String, starting empty
         t,        //  Temp-String, starting uninitialized
         S[];      //  Temp String-array, starting uninitialized
  for(s=s.replace("()","~");
                   //  Replace all "()" in the input `s` with "~"
      s.contains("(");
                   //  Loop as long as the input `s` still contains "("
      ;            //    After every iteration:
       s=s.replace(t,"")
                   //     Remove `t` from `s`
          .replace("()",""),
                   //     And also remove any redundant parenthesis groups
       r+=t+";")   //     Append `t` and a semi-colon to the result-String
    t=s.replaceAll(".*(\\([^()]+\\)).*","$1");
                   //   Set `t` to the inner-most group within parenthesis
  S=s.split(" ");  //  After the loop, split the remainder of `s` on the space
  t=S[0];          //  Set `t` to the first item (the type)
  r+=              //  Append the result-String with:
    r.isEmpty()?   //   If the result-String is empty
                   //   (so there were no parenthesis groups)
     S[1]          //    Set the result-String to the second item
    :              //   Else:
     s;            //    Simple append the remainder of `s`
  S=r.split(";");  //  Then split `r` on semi-colons
  r=S[0].replaceAll(".*?(\\w+).*",
                   //  Extract the variable name from the first item
     "$1 is ");    //  And set `r` to this name appended with " is "
  for(var p:S)     //  Loop over the parts split by semi-colons:
    r+=            //   Append the result-String with:
      p.replaceAll("[A-Za-z_]+\\d+
                   //    First remove the variable name (may contain digits)
         |[^\\[\\d]","")
                   //    And then keep only digits and "["
       .replaceAll("\\[(\\d+)",
                   //    Extract the number after "["
         "array of $1 ")
                   //    And append the result-String with "array of " and this nr
      +(p.contains("~")?
                   //    If the part contains "~"
         "function returning "
                   //     Append the result-String with "function returning "
       :           //    Else:
        "")        //     Leave the result-String the same
      +"pointer to ".repeat(
                   //    And append "pointer to " repeated
         p.split("\\*").length-1);
                   //    the amount of "*" in the part amount of time
  return r         //  Then return the result-String
          +t;}     //  appended with the temp-String (type)

Помилка в тестовому випадку із зайвими дужками.
Бубон

@Bubbler Ага, не помітив цього нового тестового випадку. На щастя, це легко виправити.
Kevin Cruijssen

6

Bash + cdecl + GNU sed, 180

cdeclце поважна утиліта Unix, яка виконує більшу частину необхідного тут, але для того, щоб відповідати вимогам вводу / виводу, sedпотрібні деякі до- та післяобробки:

sed -r 's/^/explain struct /;s/struct (int|char double|float|void) /\1 /;s/\bfunc/_func/g'|cdecl|sed -r 's/^declare //;s/as/is/;s/struct //g;s/([0-9]+) of/of \1/g;s/\b_func/func/g'
  • Не було спроб виправити граматику.

попередня обробка sed:

  • s/^/explain struct /- Додайте "пояснити структуру" до початку кожного рядка
  • s/struct (int|char double|float|void) /\1 /- Видаліть structпри роботі з типами мови С
  • s/\bfunc/_func/g - "func" розпізнається як ключове слово cdecl - придушити це

sed Післяобробка:

  • s/^declare // - видалити "оголосити" на початку рядка
  • s/as/is/ - роз'яснення
  • s/struct //g - видаліть усі ключові слова "stru"
  • s/([0-9]+) of/of \1/g - правильне впорядкування "з"
  • s/\b_func/func/g - відновити будь-який "_func", який був замінений у попередній обробці

Дія:

$ < cdecls.txt sed -r 's/^/explain struct /;s/struct (int|char double|float|void) /\1 /;s/\bfunc/_func/g'|cdecl|sed -r 's/^declare //;s/as/is/;s/struct //g;s/([0-9]+) of/of \1/g;s/\b_func/func/g'
i is int
f is pointer to float
s is array of 10 my_struct_t
func is function returning int
arr is array of 3 array of 4 int
fptrs is array of 10 pointer to function returning int
p is pointer to array of 16 pointer to float
_WTH_is_TH15 is pointer to function returning pointer to pointer to array of 1234 array of 567 _RANdom_TYPE_123
p is pointer to pointer to pointer to array of 2 pointer to function returning pointer to pointer to array of 123 pointer to array of 4 array of 5 pointer to pointer to uint32_t
p is pointer to pointer to pointer to array of 2 pointer to function returning pointer to pointer to array of 123 pointer to array of 4 array of 5 pointer to pointer to uint32_t
curried_func is function returning pointer to function returning pointer to function returning pointer to function returning pointer to function returning pointer to function returning some_type
$ 

Чи достатньо було б зробити s/\bfu/_fu/gі зберегти байти повної funcзаміни?
DLosc

чекати, це справжня утиліта? Я завжди думав, що це назва веб-сайту
phuclv

@phuclv cdecl - справжня утиліта і дуже корисна для перевірки декларацій C.
Патрісія Шанахан


Не вдалося вказати змінну as(+4 байти для пробілів). У мене немає доступу, cdeclале я думаю, що ви можете зберегти 64 байти за допомогою sed -r 's/^(\w+)(\W+)/explain struct \1_\2_/'|cdecl|sed -r 's/^declare struct _|_$//;s/ as / is /;s/([0-9]+) of/of \1/g'.
Ніл

6

Піп -s , 152 150 148 139 137 126 125 123 байт

Третій підхід!

YaRs" ("R';')R`\[(\d+)]`` array of \1`R"()"" function returning"L#aYyR`\((\**)(.+)\)`{c." pointer to"X#b}{[b"is"g@>2a]}Vy^s

Приймає декларацію як введення командного рядка. Спробуйте в Інтернеті!

Пояснення

Код складається з трьох частин: початкове налаштування та обробка функцій та масивів; петля, яка обробляє дужки та покажчики; і остаточна перестановка.

Налаштування, функції та масиви

Ми хочемо, щоб уся декларація була скобкою в дужках (це допомагає в циклі згодом), тому ми переходимо type ...;до цього type (...). Потім зауважте, що не відбувається переупорядкування описів функцій та масивів, тому ми можемо виконати всі ці заміни спочатку, не впливаючи на кінцевий результат.

Y                         Yank into y variable...
 a                        The result of a (the cmdline arg)...
  R s                     Replace the space
   " ("                    with " ("
  R ';                    Replace the semicolon
   ')                      with a closing paren
  R `\[(\d+)]`            Replace digits in square brackets
   ` array of \1`          with " array of <digits>"
  R "()"                  Replace function parens
   " function returning"   with " function returning"

Якщо наш оригінальний вклад був float *((*p()))[16];, ми тепер маємо float (*((*p function returning)) array of 16).

Дужки та покажчики

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

L#a                   Loop len(a) times (enough to complete all replacements):
 Y                    Yank into y variable...
  y                   The result of y...
   R `\((\**)(.+)\)`  Replace open paren, 0 or more asterisks (group 1), 1 or more
                      characters (group 2), and close paren
    {                  with this callback function (b = group 1, c = group 2):
     c .               The stuff in the middle, concatenated to...
      " pointer to"    that string
       X #b            repeated len(asterisks) times
    }

Приклад кроків:

float (*((*p function returning)) array of 16)
float ((*p function returning)) array of 16 pointer to
float (*p function returning) array of 16 pointer to
float p function returning pointer to array of 16 pointer to

Прибирати

Залишилося лише перемістити тип до кінця і додати "є":

{[b"is"g@>2a]}Vy^s
               y^s  Split y on spaces
{            }V     Use the resulting list as arguments to this function:
 [          ]        Return a list of:
  b                   2nd argument (the variable name)
   "is"               That string
       g@>2           All arguments after the 2nd
           a          1st argument (the type)
                    The resulting list is printed, joining on spaces (-s flag)

Для таких визначень, як int x;такий підхід, з'явиться додатковий простір, дозволений викликом.


5

JavaScript (ES6), 316 ... 268 253 байт

s=>(g=s=>[/\d+(?=])/,/\*/,/!/,/.+ /,/\w+/].some((r,i)=>(S=s.replace(r,s=>(O=[O+`array of ${s} `,O+'pointer to ','function returning '+O,O+s,s+' is '+O][i],'')))!=s)?g(S):'',F=s=>(O='',S=s.replace(/\(([^()]*)\)/,g))!=s?O+F(S):g(s)+O)(s.split`()`.join`!`)

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

Прокоментував

Функція помічника

g = s =>                             // s = expression to parse
  [                                  // look for the following patterns in s:
    /\d+(?=])/,                      //   array
    /\*/,                            //   pointer
    /!/,                             //   function
    /.+ /,                           //   type
    /\w+/                            //   variable name
  ].some((r, i) =>                   // for each pattern r at index i:
    ( S = s.replace(                 //   S = new string obtained by removing
      r,                             //       the pattern matching r from s
      s => (                         //     using the first match s and the index i,
        O = [                        //     update the output O:
          O + `array of ${s} `,      //       array
          O + 'pointer to ',         //       pointer
          'function returning ' + O, //       function
          O + s,                     //       type
          s + ' is ' + O             //       variable name
        ][i],                        //
        ''                           //     replace the match with an empty string
    )))                              //   end of replace()
    != s                             //   make some() succeed if S is not equal to s
  ) ?                                // end of some(); if truthy:
    g(S)                             //   do a recursive call with S
  :                                  // else:
    ''                               //   stop recursion and return an empty string

Основна частина

s => (                 // s = input
  g = …,               // define the helper function g (see above)
  F = s => (           // F = recursive function, taking a string s
    O = '',            //   O = iteration output, initialized to an empty string
    S = s.replace(     //   S = new string obtained by removing the next expression from s
      /\(([^()]*)\)/,  //     look for the deepest expression within parentheses
      g                //     and process it with the helper function g
    )                  //   end of replace()
  ) != s ?             // if S is not equal to s:
    O + F(S)           //   append O to the final output and do a recursive call with S
  :                    // else (we didn't find an expression within parentheses):
    g(s) + O           //   process the remaining expression with g and return O
)(s.split`()`.join`!`) // initial call to F with all strings '()' in s replaced with '!'

Мені було цікаво, чому ви використовували [...s.split`()`.join`!`]замість просто [...s.replace('()','!')], але я зрозумів, що це точно такий самий підрахунок байтів .. :)
Кевін Кройсейсен

@KevinCruijssen Основна причина полягає в тому, s.replace('()','!')що замінить лише перше виникнення.
Арнольд

Ах, звичайно. Забули заміну JS - це не те саме, що Java. У Java .replaceзамінює всі події та .replaceAllзамінює всі події включеним регулярним виразом. Завжди вважав, що названня є досить поганим для цих двох методів на Java, як я б їх назвав .replaceAllі, .regexReplaceAllабо щось у цьому напрямку, але я думаю, що для codegolf це коротше як .replaceі .replaceAll.
Кевін Круїйсен

1
До речі, я помітив, що ви використовували ту саму техніку (з ~) відразу після публікації першої версії моєї власної відповіді. Думаю, чудові розуми однаково. : p
Арнольд

3

Чисто , 415 байт

import StdEnv,Text
$s#(b,[_:d])=span((<>)' ')(init s)
=join" "(?d++[""<+b])
?[]=[]
?['()':s]=["function returning": ?s]
?['*':s]= ?s++["pointer to"]
?['[':s]#(n,[_:t])=span((<>)']')s
=["array of "<+n: ?t]
?s=case@0s of(['(':h],t)= ?(init h)++ ?t;(h,t)|t>[]= ?h++ ?t=[h<+" is"]
~c=app2((++)[c],id)
@n[c:s]=case c of'('= ~c(@(n+1)s);')'|n>1= ~c(@(n-1)s)=([c],s);_|n>0= ~c(@n s)=span(\c=c<>'('&&c<>'[')[c:s]
@_ e=(e,e)

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


3

R , 225 218 байт

g=gsub
"&"="@"=paste
"["=function(a,b)a&"array of"&b
"+"=function(a)a&"pointer to"
eval(parse(t=g('\\(\\)','@"function returning"',g('(\\w+) (.*?)([A-Za-z_]\\w*)(.*);','\\2"\\3 is"\\4&"\\1"',g('\\*','+',readline())))))

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

Повна програма, оброблена функцією на TIO для зручного тестування всіх тестових випадків одночасно.

Спочатку ми використовуємо Regex для перетворення вхідної форми type ...name...;в ..."name is"..."type". ()Потім позначення функції перетворюються на текст з оператором конкатенації з високим пріоритетом. На жаль, ми також повинні замінити *з +як колишній не є прийнятним в якості одномісний операції. Решту роблять R evalз перевантаженими операторами.


1
Розумне рішення!
J.Doe

3

Perl 6 , 209 190 171 162 153 байт

{~({(.[1]Z'is'),.<e>.&?BLOCK,('array of'X .[2]),('function returning','pointer to'Zxx.[3,0])if $_}(m:g/(\*)*[(\w+)+|\(<e=~~>.][\[(\d+).]*(\(.)*/[1]),$0)}

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

Рекурсивний підсумок регексу. Виробляє кілька додаткових символів, яких можна уникнути, ціною 3 байти .

Пояснення

{     # Anonymous block
 ~(   # Convert list to string
   {  # Block converting a regex match to a nested list
     (.[1]            # Array of 0 or 1 variable names
       Z'is'),        # zipped with string "is"
     .<e>.&?BLOCK,    # Recursive call to block with subexpression
     ('array of'      # String "array of"
       X .[2]),       # prepended to each array size
     ('function returning',  # Strings "function returning"
      'pointer to'           # and "pointer to"
      Zxx             # zipped repetition with
      .[3,0])         # number of function and pointer matches
     if $_            # Only if there's an argument
   }
   (             # Call block
     m:g/        # Input matched against regex
      (\*)*      # Sequence of asterisks, stored in [0]
      [          # Either
       (\w+)+    # the variable name, stored as 1-element array in [1]
       |         # or
       \(        # literal (
         <e=~~>  # the same regex matched recursively, stored in <e>
       .         # )
      ]
      [\[(\d+).]*  # Sequence of "[n]" with sizes stored in [2]
      (\(.)*       # Sequence of "()" stored in [3]
     /
     [1]  # Second match
   ),
   $0     # First match (base type)
 )
}

2

JavaScript на 250 байт [249?]

Тут використовується 250 байт:

k=>(a=k.match(/\W|\w+/g),s=[v=j=r=""],f=y=>!j&!a[i+1]||(m=a[i],v?(r+=v=m=='['?`array of ${a[i+=3,i-2]} `:m<')'?(i+=2,"function returning "):s[j-1]=='*'?j--&&"pointer to ":""):m==')'?v=j--|i++:m<'+'?s[j++]=a[i++]:r+=a[v=i++]+" is ",f(),r+a[0]),f(i=2))

Пояснення:

В основному, це зчитування з буфера a, який є входом маркера. Він безперервно переміщує лексеми з буфера aв стек s, поки не буде запущений режим оцінки. Режим оцінки буде споживати операції Постфіксний перші (), []з буфера, а потім він буде споживати префіксний оператор *з стека. Режим оцінювання спрацьовує, коли стан знаходиться там, де було б слово (або знайдено та вжито ім'я типу, або )знайдено та вилучити закінчення ). Режим оцінки вимикається, коли більше операторів префікса / постфікса не знайдено.

k=>( // k is input
    a=k.match(/\W|\w+/g), // split by symbol or word
    s=[v=j=r=""], // j=0, v=false, r="", s=[]
    // s is the stack, r is the return string,
    // v is true if we're in evaluation mode (Consume (), [], *)
    // v is false if we're waiting to see a ) or token, which triggers evaluation
    // j is the index of the top of the stack (Stack pointer)
    f=y=>!j&!a[i+1]||( // !j means stack is empty, !a[i+1] means we're at the ;
        m=a[i], // Save a[i] in a variable
        v // Are we evaluating?
        ?(
        r+=v=
            m=='[' // Array
            ?`array of ${a[i+=3,i-2]} ` // Skip three tokens: "[", "10", "]"
                                        // a[i-2] is the "10"
            :m<')' // m == '('
                ?(i+=2,"function returning ") // Skip two tokens: "(", ")"
                :s[j-1]=='*' // Stack has a pointer
                    ?j--&&"pointer to " // Pop the stack
                    :"" // Set v to be false, r+=""
        )
        :m==')'
            ?v=j--|i++ // Pop the '(', skip over the ')', v = Evaluation mode
            :m<'+' // m == '*' || m == '('
                ?s[j++]=a[i++] // push(s, pop(a))
                :r+=a[v=i++]+" is " // Otherwise we have the token
        , f(), r+a[0] // Recurse f(), and return r+a[0]. a[0] is the type.
    ),
    f(i=2) // Set i=2, and call f(), which returns the final value r + type
    // a = ["type", " ", ...], so i=2 give the first real token
    // This soln assumes there is only one space, which is an allowed assumption
)

ПРИМІТКА

Якщо я розумію "Використовуйте пробіл скрізь між маркерами" правильно:

k=>(a=k.split(" "),s=[v=j=r=""],f=y=>!j&!a[i+1]||(v?(r+=v=a[i]=='['?`array of ${a[i+=3,i-2]} `:a[i]<')'?(i+=2,"function returning "):s[j-1]=='*'?j--&&"pointer to ":""):a[i]==')'?v=j--|i++:a[i]<'+'?s[j++]=a[i++]:r+=a[v=i++]+" is ",f(),r+a[0]),f(i=1))

технічно справедливий і використовує

249 байт

Якщо припустити, що між кожним маркером є пробіл.


2
Це зайняло у мене багато багато годин, незважаючи на те, що це виглядає прямо. Я, мабуть, збив 5-10 байт / годину, починаючи з 350 символів. У мене справді немає життя.
Микола Піпітон

2
Мені було близько 325, коли я думав, що "я досягнув оптимальності за допомогою свого поточного алгоритму - зірвати", але потім чомусь мені все-таки вдалося стукати 5-10 / годину, незважаючи на кожен стук, який слідкував за "Добре, це, безумовно , оптимальний результат ". Удар 250 був довільним, оскільки він першим переміг правлячого 253, тому, хоча я все ще кажу "Гаразд, це, безумовно, оптимальний результат", можливо, все ще слід оптимізувати.
Микола Піпітон

1

Червоний , 418 410 байт

func[s][n: t:""a: charset[#"a"-#"z"#"A"-#"Z"#"0"-#"9""_"]parse s[remove[copy x thru" "(t: x)]to a
change[copy x[any a](n: x)]"#"]b: copy[]until[c: next find s"#"switch c/1[#"("[append
b"function returning"take/part c 2]#"["[parse c[remove[skip copy d to"]"(append b
reduce["array of"d])skip]]]#")"#";"[take c c: back back c while[#"*"= c/1][take c
c: back c append b"pointer to"]take c]]s =""]reduce[n"is"b t]]

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

Пояснення:

f: func [ s ] [
    n: t: 0                                         ; n is the name, t is the type
    a: charset [ #"a"-#"z" #"A"-#"Z" #"0"-#"9" "_" ]; characters set for parsing 
    parse s[                                        ; parse the input with the following rules
        remove [ copy x thru " " ](t: x)            ; find the type, save it to t and remove it from the string
        to a                                        ; skip to the next alphanumerical symbol
        change [ copy n [ any a ] (n: x) ] "#"      ; save it to n and replace it with '#'
    ]
    b: copy [ ]                                     ; block for the modifiers 
    until [                                         ; repeat 
       c: next find s "#"                           ; find the place of the name   
       switch c/1 [                                 ; and check what is the next symbol
           #"(" [ append b "function returning"     ; if it's a '('- it's a function - add the modifier       
                  take/part c 2                     ; and drop the "()"
                ]
           #"[" [ parse c [                         ; '[' - an array
                     remove [ skip copy d to "]"    ; save the number
                             (append b reduce [     ; and add the modifier 
                                  "array of" d
                              ] )                   
                             skip ]                 ; and remove it from the string
                     ]
                ]
           #")"                                     ; a closing bracket 
           #";" [ take c                            ; or ';' - drop it
                    c: back back c                  ; go to the left 
                    while [ #"*" = c/1 ]            ; and while there are '*'
                    [
                        take c                      ; drop them
                        c: back c                   ; go to the left
                        append b "pointer to"       ; add the modifier
                    ]
                    take c                          ; drop '(' (or space)
                 ]
       ]
       s = ""                                       ; until the string is exhausted
    ]
    reduce [ n "is" b t ]                     ; display the resul
]

0

APL (NARS), символи 625, байти 1250

CH←⎕D,⎕A,⎕a,'_'⋄tkn←nm←∆←''⋄in←⍬⋄⍙←lmt←lin←0
eb←{∊(1(0 1 0)(0 1)(1 0))[⍺⍺¨⍵]}
tb←{x←({⍵='[':3⋄⍵=']':4⋄⍵∊CH,' ':1⋄2}eb⍵)\⍵⋄(x≠' ')⊂x}

gt
tkn←''⋄→0×⍳⍙>lin⋄tkn←∊⍙⊃in⋄⍙+←1⋄→0×⍳(⍙>lin)∨'('≠↑tkn⋄→0×⍳')'≠↑⍙⊃in⋄tkn←tkn,⍙⊃in⋄⍙+←1

r←dcl;n
   n←0
B: gt⋄→D×⍳'*'≠↑tkn⋄n+←1⋄→B×⍳tkn≢''
D: r←ddcl⋄∆←∆,∊n⍴⊂'pointer to '

r←ddcl;q
   r←¯1⋄→0×⍳0>lmt-←1
   →A×⍳∼'('=↑tkn⋄q←dcl⋄→F×⍳')'=↑tkn⋄→0
A: →B×⍳∼(↑tkn)∊CH⋄nm←tkn⋄→F
B: r←¯2⋄→0
F: gt⋄→G×⍳∼tkn≡'()'⋄∆←∆,'function that return '⋄→F
G: →Z×⍳∼'['=↑tkn⋄∆←∆,'array of ',{''≡p←(¯1↓1↓tkn):''⋄p,' '}⋄→F
Z: r←0

r←f w;q
   nm←∆←''⋄in←tb w⋄⍙←1⋄lin←↑⍴in⋄lmt←150⋄gt⋄→A×⍳∼0>q←dcl⋄r←⍕q⋄→0
A: r←nm,' is a ',∆,1⊃in

це лише одне переклад з мови С на APL з коду в книзі: "Лінгваджо С" Брайана В. Кернінгана та Денніса М. Річі глава 5.12. Я не знаю, як зменшити все це, тому що я не зрозумів на 100% цей код, і тому, що я не знаю надто багато в APL ... Функція для здійснення це f; Я думаю, що дозволено лише 150 вкладених парентезів '(' ')' для повернення помилок, одне вражаюче значення з одним негативним значенням у тому чи строковому описі, якщо все нормально. Здається, це не краще, ніж інша версія, навіть якщо менше символів, оскільки інша бачить помилки краще. Деякі тести:

  f 'int f()()'
f is a function that return function that return int
  f 'int a[]()'
a is a array of function that return int
  f 'int f()[]'
f is a function that return array of int
  f 'int i;'
i is a int
  f 'float *f;'
f is a pointer to float
  f 'my_struct_t s[10];'
s is a array of 10 my_struct_t
  f 'int func();'
func is a function that return int
  f 'int arr[3][4];'
arr is a array of 3 array of 4 int
  f 'int (*fptrs[10])();'
fptrs is a array of 10 pointer to function that return int
  f 'float *(*p)[16]; '
p is a pointer to array of 16 pointer to float
  f '_RANdom_TYPE_123 (**(*_WTH_is_TH15)())[1234][567];'
_WTH_is_TH15 is a pointer to function that return pointer to pointe
  r to array of 1234 array of 567 _RANdom_TYPE_123
  f 'uint32_t (**((*(**(((*(((**(*p)))[2]))())))[123])[4])[5]);'
p is a pointer to pointer to pointer to array of 2 pointer to funct
  ion that return pointer to pointer to array of 123 pointer to
   array of 4 array of 5 pointer to pointer to uint32_t
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.