2016-09-21 1 views
0

У меня есть простой шаблон, чтобы соответствовать: голова + содержание + хвост, у меня есть ЛЕКС файл, как показано ниже:Мой шаблон lex не работает в соответствии с моим входным файлом, как его исправить?

$ cat b.l 
%{ 
#include<stdio.h> 
%} 
%% 
"12" {printf("head\n");} 
"34" {printf("tail\n");} 
.* {printf("content\n");} 
%% 

Я надеюсь, что при встрече с «12», он будет печатать «голова», когда встретить «34», он напечатает «хвост», любую другую непрерывную строку, он напечатает «контент».

Так что я скомпилировать и запустить его:

lex b.l && gcc lex.yy.c -ll 
$ echo '12sdaesre34'|a.out 
content 

Я ожидаю, он будет печатать

head 
content 
tail 

Но на самом деле он печатает только строку "содержание". У меня что-то не так, как исправить?

Спасибо!

ответ

1

(F) lex всегда соответствует максимально возможному токену. Так как .* будет соответствовать любой последовательности, не содержащей символа новой строки, он будет с удовольствием соответствовать 12sdaesre34. (В (f) lex, . соответствует любому символу, отличному от новой строки.) Таким образом, 34 больше не может быть сопоставлен.

Чтобы исправить это, вы должны быть в курсе, что вы хотите content для соответствия. Например, следующий будет соответствовать все, что не содержит цифры:

[^[:digit:]]+ { printf("content\n"); } 

Вы могли бы хотеть, чтобы добавить новую строку в списке символов не совпадают:

[^\n[:digit:]]+ { printf("content\n"); } 

Или, возможно, вы хотите соответствуют самой длинной последовательности, не содержащей 34. Это сложнее, но это может быть сделано:

([^3]|3+[^34])+ { printf("content\n"); } 

Однако, это все равно будет соответствовать первоначальному 12, поэтому он не будет достаточно, чтобы решить эту проблему.

Если ваш вход всегда состоит из строк 12...34, которые могут быть перемешаны с другим содержимым, вы можете сопоставить всю последовательность 12...34 и разделить ее на три маркера. Это, несомненно, самое простое решение, поскольку маркеры начала и конца имеют известную длину. Первый из следующих шаблонов соответствует строке, которая не запускается 12, заканчивающаяся непосредственно перед первым экземпляром 12, а вторая соответствует строке, начинающейся 12, и заканчивается в первом экземпляре 34 (что соответствует). Ни один из шаблонов не будет соответствовать входу, который содержит непревзойденный 12; поэтому добавляется третье правило для соответствия этому случаю; он очень похож на второе правило, но не включает в себя матч для 34 в конце. Поскольку (f) lex всегда совпадает с самым длинным возможным токеном, третье правило будет успешным только в случае неудачи второго правила.

([^1]|1+[^12])*   { puts("content"); } 
12([^3]|3+[^34])*34  { puts("head content tail"); } 
12([^3]|3+[^34])*  { puts("error"); } 

Обычно, вы хотели бы, чтобы фактически захватить значение content, чтобы перейти к вызывающей программе. В первом правиле это всего лишь yytext, но во втором правиле содержание состоит из yyleng-4 символов, начинающихся с yytext+2 (чтобы удалить лидирующие и конечные разделители).

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

([^1]|1+[^12])*   { yylval = strcpy(yytext); ... } 
12([^3]|3+[^34])*34  { yylval = malloc(yyleng-3); 
          memcpy(yylval, yytext, yyleng-4); 
          yylval[yyleng-4] = '\0'; 
          ... 
         } 

Те предполагают, что yylval является глобальным переменным типа char*, и что где-то в коде вы free() строка, сохраненная правилом. Они также предполагают, что вы делаете что-то с yylval в пропущенном коде (...), или что вы возвращаетесь к вызывающей стороне с указанием о том, встречались ли голова и хвост.

+0

Спасибо, но все же ответ не совсем правильный, я пробовал правило ([^ 3] | 3 + [^ 34]) + {printf ("content \ n"); } Теперь результат все равно не я wated: \t $ эха 12dsfadsf34 | a.out \t содержания \t хвоста \t содержания –

+0

@HindForsum: Да, вы совершенно правы. Я добавил несколько предложений относительно того, как вы можете продолжить, но, очевидно, это всего лишь грубая схема, потому что я действительно не знаю ваших требований. Обычно я предполагаю, что вы знакомы с строковой обработкой в ​​C. – rici

Смежные вопросы