2014-10-18 2 views
2

내가 들소를 사용하여 장난감 프로그래밍 언어에 대한 파서를 쓰고 있어요,하지만 난 벽에 충돌 한 : GNU 들소 : 예기치 않은 구문 오류는

%{ 
#include <stdio.h> 
#include "util.h" 
#include "errormsg.h" 

#define YYDEBUG 1 

int yylex(void); /* function prototype */ 

void yyerror(char *s) 
{ 
EM_error(EM_tokPos, "%s", s); 
} 
%} 

%union { 
    int pos; 
    int ival; 
    string sval; 
    } 

%token <sval> TK_ID TK_STRING 
%token <ival> TK_INT 

%token <pos>   
    TK_COMMA TK_COLON TK_SEMICOLON TK_LPAREN TK_RPAREN TK_LBRACK TK_RBRACK 
    TK_LBRACE TK_RBRACE TK_DOT TK_ASSIGN 
    TK_ARRAY TK_IF TK_THEN TK_ELSE TK_WHILE TK_FOR TK_TO TK_DO TK_LET TK_IN 
    TK_END TK_OF TK_BREAK TK_NIL 
    TK_FUNCTION TK_VAR TK_TYPE 

/* Precedence in Bison is weird: lower is higher. Take a look at the spec too. */ 
%left <pos> TK_OR 
%left <pos> TK_AND 
%nonassoc <pos> TK_EQ TK_NEQ TK_LT TK_LE TK_GT TK_GE 
%left <pos> TK_PLUS TK_MINUS 
%left <pos> TK_TIMES TK_DIVIDE 
%left <pos> TK_UMINUS   

%error-verbose 

%start program 

%% 

/* According to the spec, Tiger programs are just an expression exp. */ 
program: exp 

/* An expression can be many things; consult the spec for more info: Expressions. */ 
/* For the %prec rule, take a look at 5.4 Context-Dependent Precedence on bison manual */ 
exp: 
       lvalue 
     |  TK_NIL 
     |  exp exp_seq_aug 
     |  TK_LPAREN TK_RPAREN 
     |  TK_LET TK_IN TK_END 
     |  TK_INT 
     |  TK_STRING 
     |  TK_MINUS exp %prec TK_UMINUS 
     |  TK_ID TK_LPAREN TK_RPAREN 
     |  TK_ID TK_LPAREN exp params TK_RPAREN 
     |  exp TK_PLUS exp 
     |  exp TK_MINUS exp 
     |  exp TK_TIMES exp 
     |  exp TK_DIVIDE exp 
     |  exp TK_EQ exp 
     |  exp TK_NEQ exp 
     |  exp TK_GT exp 
     |  exp TK_LT exp 
     |  exp TK_GE exp 
     |  exp TK_LE exp 
     |  exp TK_AND exp 
     |  exp TK_OR exp 
     |  TK_ID TK_LBRACE TK_RBRACE 
     |  TK_ID TK_LBRACE TK_ID TK_EQ exp record_exp TK_RBRACE 
     |  TK_ID TK_LBRACK exp TK_RBRACK TK_OF exp 
     |  lvalue TK_ASSIGN exp 
     |  TK_IF exp TK_THEN exp TK_ELSE exp 
     |  TK_IF exp TK_THEN exp 
     |  TK_WHILE exp TK_DO exp 
     |  TK_FOR TK_ID TK_ASSIGN exp TK_TO exp TK_DO exp 
     |  TK_BREAK 
     |  TK_LET decl_seq TK_IN exp_seq_aug TK_END 
       ; 

decl_seq:   
       /* empty */ 
     |  decl_seq decl 
       ; 

decl: 
       type_decl 
     |  var_decl 
     |  func_decl 
       ; 

var_decl:  
       TK_VAR TK_ID TK_ASSIGN exp 
     |  TK_VAR TK_ID TK_COLON TK_ID TK_ASSIGN exp 
       ; 

func_decl:  
       TK_FUNCTION TK_ID TK_LPAREN type_fields TK_RPAREN TK_EQ exp 
     |  TK_FUNCTION TK_ID TK_LPAREN type_fields TK_COLON TK_ID TK_EQ exp 
       ; 

type_decl:  
       TK_TYPE TK_ID TK_EQ type 
       ; 

type:   
       TK_TYPE 
     |  TK_LBRACE type_fields TK_RBRACE 
     |  TK_ARRAY TK_OF TK_ID 
       ; 

type_fields:  
       /* empty */ 
     |  TK_ID TK_COLON TK_ID type_fields 
     |  TK_COMMA TK_ID TK_COLON TK_ID type_fields 
       ; 

lvalue:   
       TK_ID 
     |  lvalue TK_DOT TK_ID 
     |  lvalue TK_LBRACK exp TK_RBRACK 
       ;  

exp_seq:  
       /* epsilon */ 
     |  TK_SEMICOLON exp 
     |  exp_seq TK_SEMICOLON exp 
       ;  

exp_seq_aug:  
       TK_LPAREN exp_seq TK_RPAREN 
       ; 

params:   
       /* epsilon */ 
     |  params TK_COMMA exp 
       ; 
record_exp:  
       /* epsilon */ 
     |  record_exp TK_COMMA TK_ID TK_EQ exp 
       ; 

그것은이다 :

grammar.y 파일은 다음과 같다 그다지 공상적인 것은 아니며, (96) shift/reduce conflicts를 얻는다. (아마도 if 문과 함수 호출 문으로 인한 것 같다). 나는 그것이 분명하지 않아야한다는 것을 알고 있지만 같은 연습에 대한 다른 대안 구현은 더 많은 시프트/충돌을 통해 구문 분석을 깨끗하게 처리하므로 너무 많은 오류 메시지는 고려하지 않아도됩니다.

토큰 파일이 내가 얻을 %token 지침 (y.tab.h와 y.tab.c가) 및 특정 오류 메시지에서 들소에 의해 생산된다 :

매우 실망
[email protected] ~/Software/tigerc $ ./a.out tests/test4.tig 
tests/test4.tig:2.1: syntax error, unexpected TK_GE 
Parsing failed 

,

/* define a recursive function */ 
let 

/* calculate n! */ 
function nfactor(n: int): int = 
       if n = 0 
         then 1 
         else n * nfactor(n-1) 

in 
     nfactor(10) 
end 

가 어떻게 가능성이 디버깅 할 수 있습니다 : 파서가 말한다 때문에 테스트 파일이 하나도없는 때는 크거나 같은 토큰을 발견?

[편집] : 여기의 요청에 따라, 내 flex 렉서의 소스 코드입니다 : 우선 들어

%{ 
#include <string.h> 
#include "util.h" 
#include "tokens.h" 
#include "errormsg.h" 

int charPos = 1; 

int 
yywrap (void) 
{ 
    charPos = 1; 
    return 1; 
} 

// Adjust the token position in the string 
// Mainly used for error checking 
void 
adjust (void) 
{ 
    EM_tokPos = charPos; 
    charPos += yyleng; 
} 

%} 

/* Will be used for conditional activation of the comment rule. */ 
%x C_COMMENT 

digits [0-9]+ 
letters [_a-zA-Z]+ 


%% 
" " {adjust(); continue;} 
\n {adjust(); EM_newline(); continue;} 
\t  {adjust(); continue;} 

"/*"    {adjust(); BEGIN(C_COMMENT);} 
<C_COMMENT>[^*\n] {adjust();} 
<C_COMMENT>"*/" {adjust(); BEGIN(INITIAL);} 

\"(\\.|[^"])*\" {adjust(); yylval.sval = String(yytext); return STRING;} 

"," {adjust(); return COMMA;} 
";"  {adjust(); return SEMICOLON;} 
":"  {adjust(); return COLON;} 
"."  {adjust(); return DOT;} 
"+"  {adjust(); return PLUS;} 
"-"  {adjust(); return MINUS;} 
"*"  {adjust(); return TIMES;} 
"/"  {adjust(); return DIVIDE;} 
"="  {adjust(); return EQ;} 
"<>"  {adjust(); return NEQ;} 
"<"  {adjust(); return LT;} 
"<="  {adjust(); return LE;} 
">"  {adjust(); return GT;} 
">="  {adjust(); return GE;} 
"&"  {adjust(); return AND;} 
"|"  {adjust(); return OR;} 
":="  {adjust(); return ASSIGN;} 
"("  {adjust(); return LPAREN;} 
")"  {adjust(); return RPAREN;} 
"{"  {adjust(); return LBRACE;} 
"}"  {adjust(); return RBRACE;} 
"["  {adjust(); return LBRACK;} 
"]"  {adjust(); return RBRACK;} 

for  {adjust(); return FOR;} 
if  {adjust(); return IF;} 
then  {adjust(); return THEN;} 
else  {adjust(); return ELSE;} 
while {adjust(); return WHILE;} 
to  {adjust(); return TO;} 
do  {adjust(); return DO;} 
let  {adjust(); return LET;} 
in  {adjust(); return IN;} 
end  {adjust(); return END;} 
of  {adjust(); return OF;} 
break {adjust(); return BREAK;} 
nil  {adjust(); return NIL;} 
function {adjust(); return FUNCTION;} 
var  {adjust(); return VAR;} 
type  {adjust(); return TYPE;} 
array {adjust(); return ARRAY;} 

{digits}   {adjust(); yylval.ival = atoi (yytext); return INT;} 
{letters}[a-zA-Z0-9_]* {adjust(); yylval.sval = String (yytext); return ID;} 

.     {adjust(); EM_error (EM_tokPos,"illegal token");} 
+0

렉서는 어디에 있습니까? – codenheim

+0

@codenheim이 렉서 코드를 포함하도록 질문을 업데이트했습니다. – NlightNFotis

+0

좋아, 대답하고있다. 간단히 말해서 렉서는 들소 토큰 지시어로 정의 된 실제 토큰을 반환하지 않습니다. – codenheim

답변

2
How can I possibly debug this? 

, 당신은 들소 디버그 옵션을 사용하는 방법을 배우게 할 필요가있다. 그러면 모든 주를 덤프 할 것이며, 디버깅을 편안하게하기 위해 많은 시간과 인내가 필요합니다. 처음에는 문제의 원인이되는 규칙의 범위를 좁힐 수 있습니다.

문제가 해결되지 않으면 렉서는 들소가 정의한 토큰을 반환하지 않습니다.

예를 들어 Bison에 %token TK_GE이 있는데 아직 렉서가 GE을 반환합니다. Bison 문법은 TK_GE에 대해서만 알고 있으며 그것이 예상 한 것입니다. 토큰을 리콜하면 ASCII 시퀀스 위의 숫자 시퀀스를 증가시키는 것으로 정의 할 것이고, 그 값을 렉서에서 사용해야합니다.

">="  {adjust(); return TK_GE;} 

는 당신이 어딘가에 #define GE 42을 가능성이 아직 들소는 토큰을 생산하고있다 : 당신은 내가 tokens.h에서 볼 수없는 재정 어떤 종류의 일을하지 않는

, 당신은 할 렉서를 다시 작성해야 파일은 #define TK_GE 21 (예제 값)입니다.

+0

답변 주셔서 감사합니다! 나는 그것을 조사 할 것이고, 내가 끝내 자마자 곧 돌아올 것이다. – NlightNFotis

+0

렉서와 파서는 토큰 정의를 공유해야합니다. 그것은 단지 C – codenheim

+0

큰 감사입니다! 그래도 문법 오류가 발생하지만 이번에는 문법 때문이며 이해할 수없는 오류 메시지가 아닙니다!너 내가 벽돌 벽을 지나갈 수있게 도와 줬어! 필자가해야 할 일은 렉서에서 반환 된 토큰의 접두어를'TK_'로 바꾸고 토큰 정의 파일을 내 사용자 정의 파일 (tokens.h)에서 들소 ('y .tab.h') – NlightNFotis