1

후 플렉스에서 문자열을 반환 :나는 다음과 같은 코드 플렉스에 문자열을 읽고 있어요 경우 토큰 화

here에서 가져
 %x str 

    %% 
      char string_buf[MAX_STR_CONST]; 
      char *string_buf_ptr; 


    \"  string_buf_ptr = string_buf; BEGIN(str); 

    <str>\"  { /* saw closing quote - all done */ 
      BEGIN(INITIAL); 
      *string_buf_ptr = '\0'; 
      /* return string constant token type and 
       * value to parser 
       */ 
      } 

    <str>\n  { 
      /* error - unterminated string constant */ 
      /* generate error message */ 
      } 

    <str>\\[0-7]{1,3} { 
      /* octal escape sequence */ 
      int result; 

      (void) sscanf(yytext + 1, "%o", &result); 

      if (result > 0xff) 
        /* error, constant is out-of-bounds */ 

      *string_buf_ptr++ = result; 
      } 

    <str>\\[0-9]+ { 
      /* generate error - bad escape sequence; something 
       * like '\48' or '\0777777' 
       */ 
      } 

    <str>\\n *string_buf_ptr++ = '\n'; 
    <str>\\t *string_buf_ptr++ = '\t'; 
    <str>\\r *string_buf_ptr++ = '\r'; 
    <str>\\b *string_buf_ptr++ = '\b'; 
    <str>\\f *string_buf_ptr++ = '\f'; 

    <str>\\(.|\n) *string_buf_ptr++ = yytext[1]; 

    <str>[^\\\n\"]+  { 
      char *yptr = yytext; 

      while (*yptr) 
        *string_buf_ptr++ = *yptr++; 
      } 

. 이제 Flex는 yytext 또는 yytext에있는 문자 중 하나만 반환하지만 내 문자열은 'string_buf_ptr'에 저장됩니다. 스캐너에서 어떻게 검색합니까? here이 가리키고 있듯이 yytext을 현재 토큰 이상으로 수정하면 복잡 할 수 있습니다. 그래서는이 작업을 수행하는 간단한 스캐너에이 문자열을 반환하는 것입니다 : 당신이 세계로 string_buf_ptr를 선언하는 경우

ntoken = yylex(); 

while(ntoken) { 
    prinf("%s\n", yytext); 
    ntoken = yylex(); 
} 

답변

0

, 그것은 추가 수정없이 모든 코드에 액세스 할 수 있습니다. 아마 당신은 그것을 포함하고 싶을 것입니다. 및

extern char *string_buf_ptr; 

같은 같은 "myglobals.h"에 플렉스 파일에 해당 헤더 파일 (뿐만 아니라 코드가 string_buf_ptr에 액세스해야하는 다른 코드 파일)을 포함한다. 그런 다음 main()을 호출하기 전에이를 선언하십시오.

char string_buf_ptr[1024]; 

전역 변수를 사용하지 않고 메모리 버퍼를 flex로 전달하는 것이 더 좋은 방법입니다. yyextra를 사용하여이 작업을 수행 할 수 있습니다 (자세한 내용은 the Flex manual 참조). 기본적인 접근 방식은 같은 것입니다 :

struct mystruct { 
    char string_buf_ptr[1024]; /* or you can malloc this before calling flex */ 
}; 

같은 구조를 만들기 당신이는 yylex를 호출하기 전에 그런 다음, 당신이 할 수있는 같은 : 당신 렉스 코드에서 다음

main() { 
    ... 
    struct mystruct lex_data; 
    memset(&lex_data, 0, sizeof(lex_data)); 
    yylex_init_extra(&lex_data, &yyscanner_pointer); 
    ... 
    yylex(yyscanner_pointer); 
} 

, 대신에 string_buf_ptr에 대한 참조를 변경하여

((struct mystruct *)yyextra)->string_buf_ptr 

eit 그녀는 그러한 접근 방식이 효과가 없습니다.

1

이 문제에 대한 해결책은 많이 있지만, 정말로 안전한 것은 새로운 문자열 버퍼 (일반적으로 malloc)를 할당하고 입력 한 다음 호출자에게 전달하는 것뿐입니다.

호출자가 bison 생성 파서 인 경우 토큰의 "의미 적 값"이 변수 yylval에있을 것으로 예상됩니다.이 값은 공용체 일 가능성이 큽니다. 전통적인 flex/bison 스캐너/파서 배열에서 yylval은 전역입니다. 프로그램에 스캐너와 파서가 하나만 있다면 잘 작동합니다. 실제로이 프로그래밍에서는 방대한 언어 프로토 타입이 만들어졌지만 현대 프로그래밍 관점에서 보았을 때는 약간 추한 것 같습니다.

다행히, bisonflex도 진화하고 순수한 파서를 구축 할 재진입 렉서 및 bison을 구축 flex을 말함으로써 전역을 제거 할 수 있습니다. 또한 flexbison_bridge 옵션을 제공하면 yylex에 대한 정확한 호출 프로토 타입이 만들어 지므로 훨씬 더 많은 작업을 수행 할 수 있습니다.

매번 새로운 문자열 버퍼를 할당하는 단점은 파서에서 해방해야한다는 것입니다.그러나 반환 된 문자열 버퍼는 yylex에 대한 다음 호출에서 덮어 쓰지 않으므로 bison과 함께 사용할 수 있습니다. (bison 및 많은 다른 파서 생성기는 하나 이상의 (또는 더 많은) 토큰을 미리 읽을 수 있다고 가정합니다.)이 경우 렉서의 정적 상태에 의존 할 수 없습니다. bison 감소가 발생할 때까지 렉서가 이미 다시 호출되어 이전 상태를 버렸습니다.

다른 단점은 버퍼를 올바른 크기로 유지해야한다는 것입니다. 다행스럽게도 C++ 문자열을 사용하지 않아도 쉽습니다. 이것은 보통 초보자에게 권장하는 전략입니다. 여기에 이름이 W로 시작하는 특정 플랫폼에서 제외 놀라 울 정도로 효율적이다 아주 간단한 버퍼 관리 전략의 :로 할당을 조정 realloc을 사용합니다

size_t bf = 0; 
char* bfsz = 0; 
#define PUTCHAR(ch) do {    \ 
    char* newbf = realloc(bf, ++bfsz); \ 
    if (!newbf) {      \ 
    fputs("Out of memory!\n", stderr); \ 
    exit(2);       \ 
    }         \ 
    bf = newbuf;       \ 
    bf[bfsz] = ch;      \ 
    bf[bfsz+1] = 0;      \ 
} while(0) 

일부 기하 급수적으로 증가하고 실제로 충분한 공간이있는 경우 신속하게 아무것도 없습니다. 많은 realloc 구현은 그 방식으로 작동합니다. realloc에 인라인이없는 경우 해당 코드는 많은 추가 호출을 수행하므로 조금 느려집니다. 그러나 빠른 해킹을 수행하기에 충분하며 나중에 언제든지 개선 할 수 있습니다.

관련 문제