2013-03-26 70 views
0

我寫了一個語法解析速度,它在衝突「如果ELSEIF其他」如何解決這個「衝突:1個轉變/減少」

柔性文件:

%{ 
#include<stdio.h> 
#include<string.h> 
#include "context.h" 
#include "bool.h" 
#include "vtl4.tab.h" 
%} 
INT ([0-9]*) 
%% 
{INT} {return INTEGER;} 
">" {return yytext[0];} 
"(" {return yytext[0];} 
")" {return yytext[0];} 
"in" {return IN;} 
"#foreach" {return FOREACH;} 
"#end" {return END;} 
"#if" {return IF;} 
"#else" {return ELSE;} 
"#elseif" {return ELSEIF;} 
[^ \t] {yylval.string = yytext;return CONTENT;} 
[ \t] {} 
%% 

野牛文件:

%{ 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include "bool.h" 
#include "parser.h" 
#include "context.h" 
#include "vtl4.tab.h" 

extern FILE * yyin; 
extern FILE * yyout; 
extern int yylex(); 
extern int yywrap(); 
%} 

%union { 
struct simpleNode *ast; 
double d; 
int i; 
bool b; 
char* string; 
struct symbol *sym; 
} 

%token <string> CONTENT NAME 

%token IF ELSEIF ELSE END HASH DOLLAR PARENTHESIS PARENTHESIS_CLOSE LOGIC_EQUAL NEWLINE INTEGER GL 
%token FOREACH IN 
%type <ast> stmts stmt 

%nonassoc ELSEIF 
%nonassoc ELSE 

%% 
stmts 
: stmt{} 
| stmts stmt{} 
; 

stmt:CONTENT {} 
|directive {printf("stmt ---directive\n");} 
|INTEGER {} 
; 

directive:FOREACH '(' exp ')' stmts END {printf("directive ---foreach\n");} 
|if {printf("directive ---if\n");} 
; 

if:IF '(' cond ')' stmts END {printf("if\n");} 
|IF '(' cond ')' stmts ELSE stmts END {printf("if else end\n");} 
|IF '(' cond ')' stmts elseif END {printf("if elseif end\n");} 
|IF '(' cond ')' stmts elseif ELSE stmts END {printf("if elseif ... else end\n");} 
; 

elseif:ELSEIF '(' cond ')' stmts {printf("one elseif\n");} 
|elseif elseif {printf("Mul elseif\n");} 
; 

cond:INTEGER '>' INTEGER {printf("cond\n");} 

exp:INTEGER IN INTEGER {printf("exp\n");} 


%% 
int main(){ 
FILE *src; 
src = fopen("test.vm","r"); 
yyin = src; 
yyparse(); 
fclose(src); 
return 1; 
} 

int yywrap(){ 
return 1; 
} 

輸出文件說:

State 34 conflicts: 1 shift/reduce 
... 
state 34 

12 elseif: . ELSEIF '(' cond ')' stmts 
13  | . elseif elseif [ELSEIF, ELSE, END] 
13  | elseif . elseif [ELSEIF, ELSE, END] 
13  | elseif elseif . [ELSEIF, ELSE, END] 

ELSEIF shift, and go to state 25 

ELSEIF [reduce using rule 13 (elseif)] 
$default reduce using rule 13 (elseif) 

elseif go to state 34 

我查找了一些信息,併爲ELSE和ELSEIF添加了優先級,但沒有修復它。請幫助我!也許我不明白優先級機制非常好

回答

2

我不知道你希望解析的語言是如何工作的,所以這必須是猜測,但你的問題可能在這裏:

elseif : ELSEIF '(' cond ')' stmts 
    | elseif elseif 
    ; 

elseif可以由兩個elsifs組成。因此,如果您有三個elseif,它們是否應該分組爲((elseif elseif)elseif)(elseif(elseif elseif))?野牛不知道,並報告衝突。

另一件事是,如果只使用語法,而不使用其他許多代碼,則理解和使用語法要簡單得多。一個最小的編譯,並且其可讀性格式化的,你的野牛文件的版本是這樣的(假設我沒有作出任何編輯錯誤):

%token IF ELSEIF ELSE END INTEGER FOREACH IN 

%nonassoc ELSEIF 
%nonassoc ELSE 

%% 

stmts : stmt 
     | stmts stmt 
     ; 

stmt: directive | INTEGER ; 

directive : FOREACH '(' exp ')' stmts END 
      | if 
      ; 

if : IF '(' cond ')' stmts END 
    | IF '(' cond ')' stmts ELSE stmts END 
    | IF '(' cond ')' stmts elseif END 
    | IF '(' cond ')' stmts elseif ELSE stmts END 
    ; 

elseif : ELSEIF '(' cond ')' stmts 
     | elseif elseif 
     ; 

cond : INTEGER '>' INTEGER ; 

exp : INTEGER IN INTEGER ; 

%% 

我建議這個新的語法,不給任何轉變/減少衝突。

編輯:我刪除了%nonassoc優先規範,因爲它們不是必需的。對於每個IF,您正在使用帶有END的語法,因此您不會遇到類似C語法的if-if-else衝突,您可以通過指定優先級來刪除該衝突。

%token IF ELSEIF ELSE END INTEGER FOREACH IN 

%% 

stmts : stmt 
     | stmts stmt 
     ; 

stmt: directive | INTEGER ; 

directive : FOREACH '(' exp ')' stmts END 
      | if 
      ; 

if : IF '(' cond ')' stmts END 
    | IF '(' cond ')' stmts ELSE stmts END 
    | IF '(' cond ')' stmts elseifs END 
    | IF '(' cond ')' stmts elseifs ELSE stmts END 
    ; 

elseifs : elseif | elseifs elseif ; 

elseif : ELSEIF '(' cond ')' stmts 
     ; 

cond : INTEGER '>' INTEGER ; 

exp : INTEGER IN INTEGER ; 

%% 
+0

感謝您的詳細answer.It工作well.You讓我明白了這麼多,謝謝你。我會研究它甚至更嚴重,我爲我難過英語不好。 – sinory 2013-03-26 07:36:25

1

您是否閱讀過有關衝突的各種文件和其他SO問題?你應該。您會看到您的問題與ELSE無關(您引用的輸出部分在衝突中沒有提及它!)。

你的語法

elseifs: "#elseif" | elseifs elseifs 

顯然是不明確的。嘗試

elseifs: "#elseif" | elseifs "#elseif" 

或可能

elseifs: | elseifs "#elseif"