2017-12-30 80 views
0

이 코드에서 flex를 실행하면 unrecognized rule에 대해 불평합니다. (b|B)^n(a|A)^m 같은 문자열을 n >= 4 and m <= 3과 일치시키고 싶습니다. 내가 regex101에있는 정규식을 테스트하고 잘 작동합니다. 여기 코드는 다음과 같습니다flex-negative lookahead에서 인식 할 수없는 규칙

%{ 
    #include <stdio.h> 
    ... 
%} 
* some rules * 
STRING ([bB]{4,}[aA]{1,3}(?!(a|A)+))+  // rule causing error 
%% 
... 
{STRING} {  
      printf("%s ", yytext); 
     } 

편집 : 전체 문자열은 일치와 구분이 whitespace 및 \ 또는 comma입니다 허용되어야한다. 하위 문자열은 일치하지 않아야합니다.

답변

2

(F) lex는 negative lookahead assertions을 구현하지 않습니다. (참고 : 앞의 링크는 이며은 보증하지 않습니다.)

flex manual에서 flex가 허용하는 정규 표현식 연산자의 전체 목록을 찾을 수 있습니다. 그 목록에 구문이 없으면 온라인 정규 표현식 서비스가 당신에게 말하는 것과 관계없이 인식되지 않습니다. (참고 : 앞의 링크 을 보증합니다.)

(F) lex는 긍정적 인 미리보기 주장을 구현하지만 패턴의 맨 끝에 만 적용됩니다. 이것은 trailing context operator /으로 표시됩니다. 당신은 그것을가 아닌 다른 다음에 할 것을 요구하여 토큰을 인식하는 연산자를 사용할 수 있습니다

[bB]{4,}[aA]{1,3}/[^Aa] { printf("%s ", yytext); } 

하지만 상기 토큰을 인식하지 않기 때문에 즉, 꽤 동일한 의미이다 입력의 끝. 토큰 다음에는 무언가 인이 있고 A이 아니어야합니다. 다음에 이 표시되지 않습니다.은 계산되지 않습니다. 실제로 텍스트 입력에서 입력을 검색하는 경우 스트림의 마지막 문자가 줄 바꿈이라고 합리적으로 예상 할 수 있으며 줄 바꿈 문자는 [^Aa]과 일치합니다. 그러나 개행 문자가 전혀없는 텍스트 문자열을 스캔 한 다음 문제를 인식해야합니다.)

대개의 경우, 실제로는 원하는 것이 아닙니다. 또는 그것이 정말로 당신이 원하는 것이라면, (f) lex는 아마 당신의 유스 케이스와 잘 맞지 않을 것입니다.

(F) lex는 입력을 연속적인 토큰으로 나누기 위해 설계되었습니다. 토큰을 검색하지 않습니다. 현재 입력 지점에서 토큰을 식별합니다. 전체 입력은 토큰으로 구성되므로 일부 패턴은 각 포인트에서 일치해야합니다.

그 점에서 일치하지 않는 시퀀스가 ​​어떤 토큰인지 생각해야합니다. 예를 들어 보자 : 규칙과 "문자열"로 너무 많은 들이

bbbbbbbaaaa 

합니다. 그래서 무엇입니까?

  1. 유효한 토큰은 bbbbbbbaaa 시작하여 다른 토큰 하였다?

  2. 다른 패턴과 일치하는 유효한 토큰? (예 : LONG_STRING)?

  3. 유효하지 않은 토큰이 무시되어야하며 스캔을 계속할 수 있습니까?

  4. 복구 할 수없는 오류가 있습니까?

이러한 모든 경우는 검색 연산자를 사용하지 않고 처리 할 수 ​​있습니다. 첫 번째 경우

가 유효한 토큰 일치하는 정규 표현식 사용하기에 충분하다 : 두 번째 경우

[bB]{4,}[aA]{1,3}  { printf("Valid STRING: %s ", yytext); } 

를에는 (F) 렉스 최대 뭉크 매칭 규칙에 의존 할 수있는 가장 긴 일치에 해당하는 패턴이 사용됩니다 상태 : 간단하게 할 수

[bB]{4,}[aA]{1,3}  { printf("Valid STRING: %s ", yytext); } 
[bB]{4,}[aA]{4,}  { printf("Valid LONG STRING: %s ", yytext); } 

:

[bB]{4,}[aA]{1,3}  { printf("Valid STRING: %s ", yytext); } 
[bB]{4,}[aA]   { printf("Valid LONG STRING: %s ", yytext); } 

가장 긴 일치를 가진 두 패턴 중 하나를 결정하는 (f) 렉스 규칙이 입력 파일의 첫 번째 패턴을 사용하기 때문에 이것은 동일한 효과를 갖습니다. 따라서 bbbbaa---의 처음 여섯 문자는 두 패턴과 일치하므로 첫 번째 패턴은 bbbbaaaa---이 첫 번째 패턴과 일치하고 여덟 문자가 두 번째 패턴과 일치하므로 두 번째 패턴이 일치합니다.

세 번째 및 네 번째 경우에 대해 위의 패턴 쌍을 사용할 수도 있습니다. 유일한 차이점은 두 번째 패턴에 해당하는 동작에 있습니다. 사례 3의 경우 : 토큰을 무시하고 가능한 경우 경고를 발행합니다. 경우 4 : 오류 메시지를 생성하고 스캔을 종료하십시오.

+0

이 포괄적 인 답변에 감사드립니다. 사실 나는 아직도 내 문제를 해결할 수 없다. 공백이나 쉼표로 구분 된 전체 단어 만 일치시켜야하므로 원본 패턴 논리가 좋지 않다고 생각했습니다. 하위 문자열 (질문 편집)이 아닙니다. 나는이 일을 할 수 있지만 마지막에는 구분 기호가 내 성냥의 일부가된다. 이 경우에는 미리보기를 사용하는 것이 자연스러운 것처럼 보입니다. – pavlee

+1

@pavlee : 내 대답의 시작 부분에서 제기하는 질문에 대답해야합니다 : * 어떤 종류의 토큰이'bbbbaaaa '입니까? * 토큰 화기를 사용하려면 * 모든 것이 토큰이기 때문에 . (공백은 대개 묵시적이므로보고되지 않습니다.) 필자가 제안하는 두 가지 패턴의 프레임 워크는 거의 필요한 것입니다. 요점 : 가능한 가장 긴 토큰이 일치하는 것이므로 다음에 오는 것이 토큰의 일부가 될 수 없다는 것을 이미 알고 있으므로 명시 적으로 다음에 오는 것에 대해 생각할 필요가 없습니다. – rici

+1

그건 나를 위해 일을 정리, 지금 완전히 두 가지 패턴의 아이디어를 얻을 :) 나는 정규식에 대해 많은 지식을 가지고 있지 않다. 그래서 이것은 처음에 알아두면 매우 유용하다. 나는 그 대답에 감사 드린다. – pavlee