Задний план
Оператор объявления переменной в 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
Как я прочитал эти сложные заявления?
- Начните с имени переменной.
(name) is ...
- Выберите модификатор с наивысшим приоритетом.
- Прочитайте это:
* -> pointer to ...
[N] -> array of N ...
() -> function returning ...
- Повторите 2 и 3, пока модификаторы не будут исчерпаны.
- Наконец, прочитайте базовый тип.
... (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
форм единственного / множественного числа и конечную точку (точка). Каждое слово должно быть разделено одним или несколькими пробелами (пробел, табуляция, новая строка), чтобы результат был удобочитаемым.
Опять же, вот процесс преобразования:
- Начните с имени переменной.
(name) is ...
- Выберите модификатор с наивысшим приоритетом.
- Прочитайте это:
* -> pointer to ...
[N] -> array of N ...
() -> function returning ...
- Повторите 2 и 3, пока модификаторы не будут исчерпаны.
- Наконец, прочитайте базовый тип.
... (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 */
Критерий оценки и выигрыша
Это вызов для игры в гольф . Программа с наименьшим количеством байтов побеждает.
int arr[3][4];
естьan array of 3 arrays of 4 ints
(как ты говоришь) илиan array of 4 arrays of 3 ints
?sizeof(arr[0]) == sizeof(int[4])
предметarr
содержит четыреint
с.;
в конце строки?Ответы:
Python 3 ,
331 312 294 261240 байтПопробуйте онлайн!
-19 байт, переключившись на python 2 и поместив определение класса в
exec
-18 байт, изменив регулярное выражение с
[a-zA-Z_][a-zA-Z0-9_]*
на\\w+
, благодаря Кевину Круйссену-33 байта, используя магию определения класса и используя str, благодаря Линн, возвращаясь к питону 3
-21 байт, объединяя несколько регулярных выражений, благодаря infmagic2047
Требуется, чтобы во входных данных содержался только один пробел (между типом и выражением).
Я думаю, что это довольно уникальный подход к проблеме. Это главным образом использует тот факт, что сам Python может оценивать строки, такие как
(**((*(**(((*(((**(*p)))[2]))())))[123])[4])[5])
и получает правильную последовательность вызовов функций, индексов массивов и указателей - и что пользователь может перегружать их.источник
[a-zA-Z_][A-Za-z0-9_]*
в гольф, чтобы[a-zA-Z_]\\w*
сэкономить несколько байтов. РЕДАКТИРОВАТЬ: На самом деле, я думаю, что вы можете просто использовать\\w+
вместо[a-zA-Z_][A-Za-z0-9_]*
.[0]
вместо.group()
начиная с Python 3.6.Сетчатка 0.8.2 ,
142138128117 байтПопробуйте онлайн! Ссылка включает в себя тестовые случаи. Лучшая грамматика . Редактировать: Сохранено
1021 байт путем переноса решения Pip @ DLosc. Объяснение:Переместите тип в конец и оберните оставшуюся часть объявления в
()
s, если он содержит внешний*
.Обработайте любые функции.
Обработайте любые массивы.
Переместите любые указатели в конец их скобок и удалите скобки, многократно работая от самого наружного набора скобок внутрь.
Обрабатывать любые указатели.
Вставьте
is
.источник
Java 11,
469467463450 байтПопробуйте онлайн.
Объяснение:
источник
Bash + cdecl + GNU sed, 180
cdecl
является почтенной утилитой Unix, которая делает большую часть того, что здесь требуется, но для соответствия требованиям ввода / вывода требуется некотораяsed
предварительная и последующая обработка:предварительная обработка 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", которые были заменены в предварительной обработкеВ бою:
источник
s/\bfu/_fu/g
и сохранить байты полнойfunc
замены?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'
.Пип
-s
,152150148139137126125123 байтаТретий подход!
Принимает объявление в качестве ввода командной строки. Попробуйте онлайн!
объяснение
Код состоит из трех частей: первоначальная настройка и обработка функций и массивов; цикл, который обрабатывает скобки и указатели; и последняя перестановка.
Настройка, функции и массивы
Мы хотим, чтобы вся декларация заключалась в скобки (это поможет с циклом позже), поэтому мы переходим
type ...;
вtype (...)
. Затем обратите внимание, что с описаниями функций и массивов не производится переупорядочение, поэтому мы можем сначала выполнить все эти замены, не влияя на конечный результат.Если наш первоначальный вклад был
float *((*p()))[16];
, мы теперь имеемfloat (*((*p function returning)) array of 16)
.Скобки и указатели
Мы запускаем цикл, заменяя крайнюю пару круглых скобок и любые звездочки, которые находятся непосредственно внутри вводной части.
Примеры шагов:
уборка
Осталось только переместить тип в конец и добавить «is»:
Для таких определений, как
int x;
этот подход приведет к появлению дополнительного пробела, что разрешено вызовом.источник
JavaScript (ES6),
316...268253 байтаПопробуйте онлайн!
комментарии
Вспомогательная функция
Основная часть
источник
[...s.split`()`.join`!`]
вместо просто[...s.replace('()','!')]
, но я понял, что это точно такой же счетчик байтов .. :)s.replace('()','!')
он заменит только первое вхождение..replace
заменяет все вхождения и.replaceAll
заменяет все вхождения с включенным регулярным выражением. Всегда думал , что именование было очень плохо для этих двух методов в Java, как я бы назвал их.replaceAll
и.regexReplaceAll
или что - то вдоль этих линий, но я думаю , для codegolf это короче , как.replace
и.replaceAll
.~
) только после публикации первой версии моего собственного ответа. Думаю, великие умы похожи. : pЧисто , 415 байт
Попробуйте онлайн!
источник
R ,
225218 байтПопробуйте онлайн!
Полная программа, завернутая в функцию на TIO для удобного тестирования всех тестовых случаев одновременно.
Во-первых, мы используем Regex для преобразования ввода формы
type ...name...;
в..."name is"..."type"
.()
Затем нотация функций преобразуется в текст с помощью оператора сцепления с высоким приоритетом. К сожалению, мы также должны заменить*
с+
как бывший не является приемлемым в качестве одноместной операции. Остальное делают Reval
с перегруженными операторами.источник
Perl 6 ,
209190171162153 байтаПопробуйте онлайн!
Рекурсивный подход регулярных выражений. Создает дополнительные символы пробела, которых можно избежать за счет 3 байтов .
объяснение
источник
JavaScript 250 байт [249?]
Это использует 250 байт:
Объяснение:
По сути, это чтение из буфера
a
, который является входным токеном. Он непрерывно перемещает токены из буфераa
в стекs
до тех пор, пока не будет запущен режим оценки. Режим оценки будет потреблять операции постфиксных первые()
,[]
из буфера, а затем он будет потреблять префиксный оператор*
из стека. Режим оценки запускается, когда в состоянии находится слово (либо имя типа найдено и использовано, либо окончание)
найдено и удалено). Режим оценки деактивируется, когда префиксные / постфиксные операторы больше не обнаружены.НОТА
Если я правильно понимаю, "Используйте пробел везде между токенами" правильно:
технически обоснован и использует
249 байт
Предполагая, что между каждым токеном есть пробел.
источник
Красный ,
418410 байтПопробуйте онлайн!
Объяснение:
источник
APL (NARS), символы 625, байты 1250
это всего лишь один перевод из языка C в APL из кода в книге: «Linguaggio C» Брайана У. Кернингхана и Денниса М. Ричи, глава 5.12. Я не знаю, как уменьшить все это, потому что я не понял этого кода на 100%, а также потому, что я не слишком разбираюсь в APL ... Функция для упражнения это f; я думаю, что допускается только 150 вложенных парентезов '(' ')' для ошибки, возвращаются одна стринг с одним отрицательным значением в этом или удаление строки, если все в порядке. Кажется, что это не лучше, чем в другой версии, даже если меньше символов, потому что другой лучше видит ошибки. Некоторый тест:
источник