열려있는 파일을 어떻게 처리 할 수 있습니까? 다른 스캐너에서 다음 스캐너로 읽은 다음 파서에 넘겨 주시겠습니까?flex/bison : 동일한 입력 파일에서 두 개의 렉서를 전환하는 방법
답변
플렉스 버퍼를 한 스캐너에서 다른 스캐너로 쉽게 전송할 수 없습니다. 많은 세부 사항은 스캐너 전용이므로 리버스 엔지니어링해야하므로 유지 관리가 불가능합니다.
그러나 의미 유형이 호환되는 한, 하나 이상의 스캐너 정의를 두 개 (또는 그 이상) 결합하는 것은 어렵지 않습니다. 다른 시작 조건을 부여하기 만하면됩니다. 시작 조건은 스캐너 작업 외부에서도 설정할 수 있으므로 한 스캐너 정의에서 다른 스캐너 정의로 전환하는 것이 쉽습니다.
플렉스 스캐너는 테이블 기반이므로 두 스캐너를 결합하는 데 실제 비효율적이지 않습니다. 실제로 코드를 복제하지 않을 경우 가치가있을 수 있습니다. 결합 된 테이블은 개별 테이블의 합계보다 약간 클 수 있습니다. 그 이유는 더 많은 문자 등가 클래스가있을 가능성이 있기 때문입니다. 반면에 더 큰 테이블은 더 나은 테이블 압축을 허용 할 수 있습니다. 이 두 가지 효과 중 어느 것도 눈에 띄기 쉽지 않습니다.
다음은 간단하지만 유용한 예입니다. 이 파서는 파일을 읽고 평가 된 표현식으로 ${arithmetic expressions}
을 대체합니다. (그저보기에 불과하므로 아주 기본적인 표현식 만 허용되지만 쉽게 확장 할 수 있어야합니다.)
어휘 스캐너는 시작 조건 SC_ECHO
에서 시작해야하므로 초기화해야합니다. 개인적으로이 간단한 경우에 초기화를 피하려면 INITIAL
부터 시작하는 것이 좋지만 때로는 스캐너가 다양한 시작 조건을 처리 할 수 있어야하므로 코드를 남겨 두었습니다. 오류 처리 기능은 개선 될 수 있지만 기능적입니다.
파서는 매우 간단한 error
규칙을 사용하여 재 동기화하고 대체 오류를 추적합니다. 비 단말기의 의미 론적 값 subst
, file
및 start
은 파일의 오류 카운트입니다. 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);
}
답변 해 주셔서 감사합니다!헤더와 같은 것을 "겹쳐 쓰고 싶습니다"-하지만 현재는 "두 번째"스캐너에서 인식되는 일부 키워드가 포함되어 있기 때문에 질문이 떠 올랐습니다. "문맥 의존"스캐너 규칙을 어떻게 바꿀 수 있습니까? 생략해야하는 헤더의 "구문"을 정의하지 않고 그것은 정규 표현식 때문일 수 있습니다. "아무것도"를 건너 뛰고 싶지만 토큰을 구분 기호와 식별자에 할당해야한다면 문제가 생깁니다 ... – sqller
더 많은 공간이 필요합니다. 물론 헤더를 수동으로 인식 할 수 있습니다. - 두 번째 스캐너와 파서로 핸드 오버 -이 작동합니다 -하지만 난 "언어"lex 파일에 분리 된 유지 - 하드 코딩되지. – sqller
아 - 스캐너 시작 조건과 그 목적을 알지 못했습니다. 생산/파서의 시작 기호에 대해 더 많이 생각해보십시오. 시도해 볼 것입니다 - 어떻게 다루는지를 잘 이해하면됩니다. – sqller
왜 여기에 파일입니까? 시작 상태를 밀어 동일한 스캐너에서 다른 규칙 집합으로 전환하고 빠져 나오려는 순간 팝업하십시오. – EJP
rici의 답변을 확인하십시오. – akim