Считайте объявление переменной C

42

Задний план

Оператор объявления переменной в 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 постфиксные операторы имеют приоритет над префиксными операторами, и модификаторы типов не являются исключением. Поэтому []и ()связывай сначала, потом *. Все, что находится в паре паренов (...)(не путать с оператором функции), сначала связывается с чем-либо снаружи.

Иллюстрированный пример:

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_]*.
  • Теоретически, ваша программа должна поддерживать неограниченное количество модификаторов типов.

Вы можете упростить другие элементы синтаксиса C следующими способами (полная реализация также приветствуется):

  • Базовый тип всегда одно слово, например 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
user202729
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с.
Bubbler
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+, благодаря Кевину Круйссену

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

-21 байт, объединяя несколько регулярных выражений, благодаря infmagic2047

Требуется, чтобы во входных данных содержался только один пробел (между типом и выражением).

Я думаю, что это довольно уникальный подход к проблеме. Это главным образом использует тот факт, что сам Python может оценивать строки, такие как (**((*(**(((*(((**(*p)))[2]))())))[123])[4])[5])и получает правильную последовательность вызовов функций, индексов массивов и указателей - и что пользователь может перегружать их.

Черная сова Кай
источник
1
Хороший подход, +1 от меня! Вы можете играть [a-zA-Z_][A-Za-z0-9_]*в гольф, чтобы [a-zA-Z_]\\w*сэкономить несколько байтов. РЕДАКТИРОВАТЬ: На самом деле, я думаю, что вы можете просто использовать \\w+вместо [a-zA-Z_][A-Za-z0-9_]*.
Кевин Круйссен
Мне нравится такой подход :) вот он в 253 байтах
Линн
1
Неплохо подмечено. 261 это тогда.
Линн
1
Вы можете использовать [0]вместо .group()начиная с Python 3.6.
infmagic2047
1
И вот версия 240 байт .
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
@Bubbler Ах, я не заметил этот новый тест. К счастью, это легко исправить.
Кевин Круйссен
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 - удалить все ключевые слова "struct"
  • 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 - настоящая утилита, которая действительно полезна для проверки объявлений на языке Си.
Патриция Шанахан
Сбой для переменной с именем 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

уборка

Осталось только переместить тип в конец и добавить «is»:

{[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;этот подход приведет к появлению дополнительного пробела, что разрешено вызовом.

DLosc
источник
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 '!'
Arnauld
источник
Мне было интересно, почему вы использовали [...s.split`()`.join`!`]вместо просто [...s.replace('()','!')], но я понял, что это точно такой же счетчик байтов .. :)
Кевин Круйссен
@KevinCruijssen Основная причина заключается в том, что s.replace('()','!')он заменит только первое вхождение.
Арно
Ах, конечно. Забытая замена JS - это не то же самое, что замена Java. В Java .replaceзаменяет все вхождения и .replaceAllзаменяет все вхождения с включенным регулярным выражением. Всегда думал , что именование было очень плохо для этих двух методов в Java, как я бы назвал их .replaceAllи .regexReplaceAllили что - то вдоль этих линий, но я думаю , для codegolf это короче , как .replaceи .replaceAll.
Кевин Круйссен
1
Кстати, я заметил, что вы использовали ту же технику (с ~) только после публикации первой версии моего собственного ответа. Думаю, великие умы похожи. : p
Arnauld
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)

Попробуйте онлайн!

Οurous
источник
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)
 )
}
nwellnhof
источник
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

это всего лишь один перевод из языка C в APL из кода в книге: «Linguaggio C» Брайана У. Кернингхана и Денниса М. Ричи, глава 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
RosLuP
источник