2016-08-25 12 views
0

열려있는 파일을 어떻게 처리 할 수 ​​있습니까? 다른 스캐너에서 다음 스캐너로 읽은 다음 파서에 넘겨 주시겠습니까?flex/bison : 동일한 입력 파일에서 두 개의 렉서를 전환하는 방법

+0

왜 여기에 파일입니까? 시작 상태를 밀어 동일한 스캐너에서 다른 규칙 집합으로 전환하고 빠져 나오려는 순간 팝업하십시오. – EJP

+0

rici의 답변을 확인하십시오. – akim

답변

3

플렉스 버퍼를 한 스캐너에서 다른 스캐너로 쉽게 전송할 수 없습니다. 많은 세부 사항은 스캐너 전용이므로 리버스 엔지니어링해야하므로 유지 관리가 불가능합니다.

그러나 의미 유형이 호환되는 한, 하나 이상의 스캐너 정의를 두 개 (또는 그 이상) 결합하는 것은 어렵지 않습니다. 다른 시작 조건을 부여하기 만하면됩니다. 시작 조건은 스캐너 작업 외부에서도 설정할 수 있으므로 한 스캐너 정의에서 다른 스캐너 정의로 전환하는 것이 쉽습니다.

플렉스 스캐너는 테이블 기반이므로 두 스캐너를 결합하는 데 실제 비효율적이지 않습니다. 실제로 코드를 복제하지 않을 경우 가치가있을 수 있습니다. 결합 된 테이블은 개별 테이블의 합계보다 약간 클 수 있습니다. 그 이유는 더 많은 문자 등가 클래스가있을 가능성이 있기 때문입니다. 반면에 더 큰 테이블은 더 나은 테이블 압축을 허용 할 수 있습니다. 이 두 가지 효과 중 어느 것도 눈에 띄기 쉽지 않습니다.


다음은 간단하지만 유용한 예입니다. 이 파서는 파일을 읽고 평가 된 표현식으로 ${arithmetic expressions}을 대체합니다. (그저보기에 불과하므로 아주 기본적인 표현식 만 허용되지만 쉽게 확장 할 수 있어야합니다.)

어휘 스캐너는 시작 조건 SC_ECHO에서 시작해야하므로 초기화해야합니다. 개인적으로이 간단한 경우에 초기화를 피하려면 INITIAL부터 시작하는 것이 좋지만 때로는 스캐너가 다양한 시작 조건을 처리 할 수 ​​있어야하므로 코드를 남겨 두었습니다. 오류 처리 기능은 개선 될 수 있지만 기능적입니다.

파서는 매우 간단한 error 규칙을 사용하여 재 동기화하고 대체 오류를 추적합니다. 비 단말기의 의미 론적 값 subst, filestart은 파일의 오류 카운트입니다. expr의 의미 론적 값은 표현식의 값입니다. 이 간단한 경우에는 두 정수가 모두 정수이므로 yylval의 기본 유형이 작동합니다.

끝나지 않은 대체는 정상적으로 처리되지 않습니다. 특히, 대체를 위해 어휘 스캔 중에 EOF를 읽으면 출력에 표시가 삽입되지 않습니다. 나는 그것을 운동으로 고쳐 둡니다. 모든 것이 잘 가고, 그렇지 않으면 잘못된 대체의 수는 (문제를 모듈로하면 0을 반환

int parseFile(FILE *in, *out); 

:

%{ 
#include "xsub.tab.h" 
%} 
%option noinput nounput noyywrap nodefault 
%option yylineno 
%x SC_ECHO 
%% 
    /* In a reentrant lexer, this would go into the state object */ 
    static int braces; 

    /* This start condition just echos until it finds ${... */ 
<SC_ECHO>{ 
    "${"  braces = 0; BEGIN(INITIAL); 
    [^$\n]+  ECHO; 
    "$"   ECHO; 
    \n   ECHO; 
} 
/* We need to figure out where the substitution ends, which is why we can't 
    * just use a standard calculator. Here we deal with terminations. 
    */ 
"{"   ++braces; return '{'; 
"}"   { if (braces) { --braces; return '}'; } 
       else  { BEGIN(SC_ECHO); return FIN; } 
       } 

/* The rest is just a normal calculator */ 
[0-9]+  yylval = strtol(yytext, NULL, 10); return NUMBER; 
[[:blank:]]+ /* Ignore white space */ 
\n   /* Ignore newlines, too (but could also be an error) */ 
.    return yytext[0]; 

%% 
void initialize_scanner(void) { 
    BEGIN(SC_ECHO); 
} 

파서는 단일 인터페이스를 보냅니다 :) 여기

는 렉서의 종단되지 않은 치환과 함께 상기 언급 됨).

%{ 
#include <stdio.h> 
int yylex(void); 
void yyerror(const char* msg); 
void initialize_scanner(void); 

extern int yylineno; 
extern FILE *yyin, *yyout; 
%} 
%token NUMBER FIN UNOP 
%left '+' '-' 
%left '*' '/' '%' 
%nonassoc UNOP 

%define parse.lac full 
%define parse.error verbose 
%% 
start: file   { if ($1) YYABORT; else YYACCEPT; } 
file :    { $$ = 0; } 
    | file subst { $$ = $1 + $2; } 
subst: expr FIN  { fprintf(yyout, "%d", $1); $$ = 0; } 
    | error FIN  { fputs("${ BAD SUBSTITUTION }", yyout); $$ = 1; } 
expr : NUMBER 
    | '-' expr %prec UNOP { $$ = -$2; } 
    | '(' expr ')' { $$ = $2; } 
    | expr '+' expr { $$ = $1 + $3; } 
    | expr '-' expr { $$ = $1 - $3; } 
    | expr '*' expr { $$ = $1 * $3; } 
    | expr '/' expr { $$ = $1/$3; } 
    | expr '%' expr { $$ = $1 % $3; } 
%% 
void yyerror(const char* msg) { 
    fprintf(stderr, "%d: %s\n", yylineno, msg); 
} 

int parseFile(FILE* in, FILE* out) { 
    initialize_scanner(); 
    yyin = in; 
    yyout = out; 
    return yyparse(); 
} 

그리고 간단한 드라이버 :

#include <stdio.h> 
int parseFile(FILE* in, FILE* out); 
int main() { 
    return parseFile(stdin, stdout); 
} 
+0

답변 해 주셔서 감사합니다!헤더와 같은 것을 "겹쳐 쓰고 싶습니다"-하지만 현재는 "두 번째"스캐너에서 인식되는 일부 키워드가 포함되어 있기 때문에 질문이 떠 올랐습니다. "문맥 의존"스캐너 규칙을 어떻게 바꿀 수 있습니까? 생략해야하는 헤더의 "구문"을 정의하지 않고 그것은 정규 표현식 때문일 수 있습니다. "아무것도"를 건너 뛰고 싶지만 토큰을 구분 기호와 식별자에 할당해야한다면 문제가 생깁니다 ... – sqller

+0

더 많은 공간이 필요합니다. 물론 헤더를 수동으로 인식 할 수 있습니다. - 두 번째 스캐너와 파서로 핸드 오버 -이 작동합니다 -하지만 난 "언어"lex 파일에 분리 된 유지 - 하드 코딩되지. – sqller

+0

아 - 스캐너 시작 조건과 그 목적을 알지 못했습니다. 생산/파서의 시작 기호에 대해 더 많이 생각해보십시오. 시도해 볼 것입니다 - 어떻게 다루는지를 잘 이해하면됩니다. – sqller