Codegolf — Компиляция Регулярных Выражений

  • Автор темы Bangis
  • Обновлено
  • 22, Oct 2024
  • #1

В этой задаче вам нужно написать программу, которая считывает регулярное выражение и генерирует другую программу, которая выводит информацию о том, принимается ли входная строка этим регулярным выражением. Результатом должна быть программа, написанная на том же языке, что и ваша заявка.

Вход

Входные данные представляют собой регулярное выражение р соответствующее следующему ABNF (исходное производственное правило

 
 
 (0|1(0|1)*)(|A(0|1)*1) 
):

#include <stdio.h> int main() { char input[65536]; int state = 0; for (;;) switch (state) { case 0: switch (getchar()) { case 'a': state = 1; break; case 'b': state = 2; break; case EOF: return 0; default: return 1; } break; case 1: switch (getchar()) { case 'b': state = 2; break; case EOF: return 0; default: return 1; } break; case 2: switch (getchar()) { case 'a': state = 1; break; case EOF: return 0; default: return 1; } break; }

Если входные данные не соответствуют этой грамматике, поведение вашей программы не определено.

Интерпретация

Интерпретируйте ввод как регулярное выражение, где babba is the Kleene-star (meaning повторить левый аргумент ноль или более раз), foo is an alternative, afba и abab group and no operator at all concatenated. Grouping takes precedence over star, star takes precedence over concatenation, concatenation takes precedence over alternative.

Говорят, что строка принял если регулярное выражение соответствует всей строке.

Выход

Результатом работы программы является другая программа, написанная на том же языке, что и ваша заявка, которая читает строку. с определенным реализацией способом во время выполнения, выводит, р принимает с и затем прекращается. Вывод может выполняться способом, определяемым пользователем, хотя должно быть только два различных вывода для принятых и отклоненных программ.

Вы можете предположить, что входные данные вашей программы вывода никогда не длиннее 216-1 байт.

Ограничения

Ни ваша заявка, ни любая программа, созданная на основе вашей заявки, не может использовать встроенные функции или библиотеки, которые

  • сопоставлять регулярные выражения
  • преобразовывать регулярные выражения
  • компилировать регулярные выражения
  • генерировать парсеры из грамматики
  • упростить задачу так, чтобы ваше представление стало тривиальным

Подсчет очков

Оценка вашего представления — это количество символов в нем. Побеждает работа с наименьшим количеством баллов.

Тестовые случаи

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

(пустое регулярное выражение)

Принятые строки

  1. (пустой ввод)

Отклоненные строки

  1. фу
  2. бар
  3. Баз
  4. Quux

Пример программы

abababababa

ba ( a и b alternating)

принятые строки

  1. a
  2. (b|)(ab)*(a|)
  3. #include <stdio.h> int main() { char input[65536]; gets(input); return input[0] != 0; }
  4. )

отклоненные строки

  1. (
  2. |
  3. *

пример программы

REGEX = *( STAR / GROUP / LITERAL / ALTERNATIVE ) STAR = REGEX '*' GROUP = '(' REGEX ')' LITERAL = ALPHA / DIGIT ALTERNATIVE = REGEX '|' REGEX

REGEX (binary floating point numbers)

принятые строки

  1. 10110100
  2. 0
  3. 1A00001

отклоненные строки

  1. 011
  2. 10А
  3. 1А00
  4. 100А010

#код-гольф #регулярное выражение #генерация кода #генерация

Bangis


Рег
16 Apr, 2004

Тем
71

Постов
205

Баллов
570
  • 26, Oct 2024
  • #2

С, 627 символов

Эта программа рассматривает свой первый аргумент командной строки как входные данные и генерирует код C в качестве выходных данных.

 
 
 
 
 
 >>> a|bc

s=[0, 1, 3, 4];
gets.chop.chars.map{|c|

s=s.map{|s|s==1&&c=='a'&&2||s==4&&c=='b'&&5||s==6&&c=='c'&&7}-[!0];

s&[0]!=[]&&s|=[0, 1, 3, 4];

s&[3]!=[]&&s|=[3, 4];

s&[5]!=[]&&s|=[5, 6];

s&[2]!=[]&&s|=[2, 7]
};
p s&[7]!=[]
 

Вот его вывод для >>> (b|)(ab)*(a|) s=[0, 1, 2, 4, 9, 5, 10, 6, 11, 12, 14]; gets.chop.chars.map{|c| s=s.map{|s|s==2&&c=='b'&&3||s==6&&c=='a'&&7||s==8&&c=='b'&&9||s==12&&c=='a'&&13}-[!0]; s&[1]!=[]&&s|=[1, 2, 4, 9, 5, 10, 6, 11, 12, 14]; s&[3]!=[]&&s|=[3, 4, 9, 5, 10, 6, 11, 12, 14]; s&[0]!=[]&&s|=[0, 1, 2, 4, 9, 5, 10, 6, 11, 12, 14]; s&[5]!=[]&&s|=[5, 6]; s&[7]!=[]&&s|=[7, 8]; s&[9]!=[]&&s|=[9, 5, 10, 6, 11, 12, 14]; s&[4]!=[]&&s|=[4, 9, 5, 10, 6, 11, 12, 14]; s&[11]!=[]&&s|=[11, 12, 14]; s&[13]!=[]&&s|=[13, 14]; s&[10]!=[]&&s|=[10, 11, 12, 14] }; p s&[14]!=[] (with newlines added):

>>> s=[0]; gets.chop.chars.map{|c| s=s.map{|s|}-[!0]; }; p s&[0]!=[]

Если вы предоставляете действительные входные данные в качестве первого аргумента командной строки, он возвращает статус выхода 1. В противном случае он возвращает статус выхода 0.

$ ./regexcompiler '(0|1(0|1)*)(|A(0|1)*1)' > floatprog.c
$ gcc -o floatprog floatprog.c
floatprog.c: В функции «main»:
floatprog.c:1:519: предупреждение: несовместимое неявное объявление встроенной функции «exit» [включено по умолчанию]
$ ./floatprog '1A00001' && неверный вывод || эхо действительно
действительный
$ ./floatprog '100A010' && неверный вывод || эхо действительно
неверный

Любая программа, если вы не указали аргумент командной строки, разыменовывает нулевой указатель, вызывая ошибку сегментации. Достаточно длинное регулярное выражение переполнит буферы этой отправки, а размер ввода в сгенерированную программу ограничен размером стека. Однако все тестовые примеры работают.

Обратите внимание, что H=Hash.new{|h,k|[k]} d=[[i=0,0,[]]] o=[?(] L="t,u,v=d.pop;q,r,s=d.pop;o.pop<?|&&(H[r]<<=t)||(H[q]<<=t;H[r]<<=u);d<<[q,u,s+v]" gets.chop.chars.map{|c|c==?*&&(q,r,s=d.pop;H[r]|=[q,i+=1];d<<=[r,i,s];next) eval(L)while/[|)]/=~c ?o[-1]>?(:o[-1]==?. /[|(]/=~c&&d<<[i+=1,i,o<<c&&[]]||c!=?)&&d<<[i+=1,i+1,["s==#{o<<?.;i}&&c=='#{c}'&&#{i+=1}"]]||o[-1]=?.} eval(L)while o.size>1 H.map{H.map{|k,v|v.map{|v|H[k]|=H[v]}}} t,u,v=d[0] $><<"s=#{H[t]};gets.chop.chars.map{|c|s=s.map{|s|#{v*'||'}}-[!0];#{H.map{|k,v|"s&[#{k}]!=[]&&s|=#{v}"}*?;}};p s&[#{u}]!=[]" introduces undefined behavior. If, for example, generated programs do not compile, you can try replacing the statement with h+=2;e(g=h-1,C=h-2,0,0); , что на пять символов длиннее.

 

Sustro


Рег
25 Mar, 2020

Тем
79

Постов
213

Баллов
628
  • 26, Oct 2024
  • #3

Рубин, 641 651 543 символов

e(g=h++,C=h++,0,0);

Эта версия Ruby стала довольно длинной из-за нескольких угловых случаев в анализаторе регулярных выражений (возможно, мне стоит попробовать другой подход). Он ожидает регулярного выражения на STDIN и выводит соответствующий код Ruby для сопоставителя на STDOUT.

Программа напрямую генерирует код для NFA-ε, который затем выполняется в сопоставителе.

Тестовый пример 1: (вывод включает дополнительные символы новой строки и отступы)

f11(char*s){return 1&&s[0]==49&&f7(s+1);} f10(char*s){return 1&&s[0]==48&&f9(s+1)||1&&s[0]==49&&f9(s+1);} f9(char*s){return 1&&f10(s)||f11(s);} f8(char*s){return 1&&f7(s+0)||1&&s[0]==65&&f9(s+1);} f7(char*s){return 1&&f0(s+0);} f6(char*s){return 1&&f2(s+0);} f5(char*s){return 1&&s[0]==48&&f4(s+1)||1&&s[0]==49&&f4(s+1);} f4(char*s){return 1&&f5(s)||f6(s);} f3(char*s){return 1&&s[0]==48&&f2(s+1)||1&&s[0]==49&&f4(s+1);} f2(char*s){return 1&&f8(s+0);} f1(char*s){return 1&&f3(s+0);} f0(char*s){return 1&&!*s;} main(int c,char**v){exit(f1(v[1]));}

Тестовый пример 2:

(0|1(0|1)*)(|A(0|1)*1)

Другой пример:

#define A(v) F[v]+strlen(F[v]) #define S sprintf char*B="&&f%d(s)||f%d(s)",*J="&&f%d(s+%d)",*r,F[256][65536];h=2;e(f,n,o,R,C,O,t,g){for(C=O=f;*r;++r)switch(*r){case 40:r++;e(g=h++,C=h++,0,0);r[1]^42?t=g:(t=C,S(A(t),B,g,C=h++),r++);o=!S(A(O),J,t,o);O=C;break;case 41:goto L;case'|':S(A(C),J,n,o);o=!S(A(O=f),"||1");break;default:r[1]^42?S(A(C),"&&s[%d]==%d",o++,*r,O^f||R++):(o=!S(A(O),J,t=h++,o),O=C=h++,g=h++,S(A(g),"&&*s==%d&&f%d(s+1)",*r++,t),S(A(t),B,g,C));}L:S(A(C),J,n,o);}main(int c,char**v){r=v[1];for(e(1,!S(*F,"&&!*s"),0,0);h--;)printf("f%d(char*s){return 1%s;}",h,F[h]);puts("main(int c,char**v){exit(f1(v[1]));}");}

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

 

PAVEL1986


Рег
21 May, 2011

Тем
62

Постов
193

Баллов
513
Тем
403,760
Комментарии
400,028
Опыт
2,418,908