簡體   English   中英

修復野牛語法中的移位/減少沖突

[英]Fix shift/reduce conflict in bison grammar

我為解析文本文件編寫的野牛語法給了我10個移位/減少沖突的機會。 parser.output文件對我的幫助不足。 該文件為我提供了以下信息:

State 38 conflicts: 5 shift/reduce
State 40 conflicts: 4 shift/reduce
State 46 conflicts: 1 shift/reduce

Grammar

0 $accept: session $end

1 session: boot_data section_start

2 boot_data: head_desc statement head_desc head_desc

3 head_desc: OPEN_TOK BOOT_TOK statement CLOSE_TOK
4          | OPEN_TOK statement CLOSE_TOK

5 statement: word
6          | statement word

7 word: IDENTIFIER
8     | TIME
9     | DATE
10     | DATA

11 section_start: section_details
12              | section_start section_details
13              | section_start head_desc section_details

14 $@1: /* empty */

15 section_details: $@1 section_head section_body section_end

16 section_head: START_TOK head_desc START_TOK time_stamp

17 time_stamp: statement DATE TIME

18 section_body: log_entry
19             | section_body log_entry

20 log_entry: entry_prefix body_statements
21          | entry_prefix TIME body_statements

22 body_statements: statement
23                | head_desc

24 entry_prefix: ERROR_TOK
25             | WARN_TOK
26             | /* empty */

27 $@2: /* empty */

28 section_end: END_TOK statement $@2 END_TOK head_desc

 state 38

 8 word: TIME .
21 log_entry: entry_prefix TIME . body_statements

 OPEN_TOK    shift, and go to state 1
 TIME        shift, and go to state 6
 DATE        shift, and go to state 7
 DATA        shift, and go to state 8
 IDENTIFIER  shift, and go to state 9

 OPEN_TOK    [reduce using rule 8 (word)]
 TIME        [reduce using rule 8 (word)]
 DATE        [reduce using rule 8 (word)]
 DATA        [reduce using rule 8 (word)]
 IDENTIFIER  [reduce using rule 8 (word)]
 $default    reduce using rule 8 (word)

 head_desc        go to state 39
 statement        go to state 40
 word             go to state 11
 body_statements  go to state 45


state 39

23 body_statements: head_desc .

$default  reduce using rule 23 (body_statements)


state 40

6 statement: statement . word
22 body_statements: statement .

TIME        shift, and go to state 6
DATE        shift, and go to state 7
DATA        shift, and go to state 8
IDENTIFIER  shift, and go to state 9

TIME        [reduce using rule 22 (body_statements)]
DATE        [reduce using rule 22 (body_statements)]
DATA        [reduce using rule 22 (body_statements)]
IDENTIFIER  [reduce using rule 22 (body_statements)]
$default    reduce using rule 22 (body_statements)

word  go to state 19

state 46

9 word: DATE .
17 time_stamp: statement DATE . TIME

TIME  shift, and go to state 48

TIME      [reduce using rule 9 (word)]
$default  reduce using rule 9 (word)

我的語法的等效部分是:

statement : word
    {
        printf("WORD\n");
        $$=$1;
    }
    |statement word
    {
        printf("STATEMENTS\n");
        $$=$1;
        printf("STATEMENT VALUE== %s\n\n",$$);
    }
    ;

 word : IDENTIFIER
    {
        printf("IDENTIFIER\n");
        $$=$1;
    }
    |TIME
    {
        printf("TIME\n");
        $$=$1;
    }
    |DATE
    {
        printf("DATE\n");
        $$=$1;
    }
    |DATA
    {
    }
    ;
section_start : section_details 
    {
        printf("SINGLE SECTIONS\n");        
    }
    |section_start section_details
    {
        printf("MULTIPLE SECTIONS\n");   
    }
    |section_start head_desc section_details
    ;

section_details :
        {
             fprintf(fp,"\n%d:\n",set_count); 
        }
         section_head section_body section_end
         {
            printf("SECTION DETAILS\n");
             set_count++;

        }
         ;

section_head : START_TOK head_desc START_TOK statement time_stamp
         {
            printf("SECTION HEAD...\n\n%s===\n\n%s\n",$2,$4);
            fprintf(fp,"%s\n",$4);

         }
         ;
time_stamp : DATET TIME
    {

    }
    ;
section_body :log_entry
         {

         }
        |section_body log_entry
         {

         }
         ;

log_entry : entry_prefix body_statements
         {

         }
         |entry_prefix TIME body_statements
         {

        }
        ;

body_statements : statement
        {

        }
        |head_desc
        {

        }
        ;

請幫我解決這個問題。

謝謝

yacc / bison解析器中的沖突意味着語法不是LALR(1)-通常意味着某些東西是模棱兩可的或者需要超過1個超前標記。 默認解決方案是選擇始終轉換為減少,或選擇始終減少第一個規則(以減少/減少沖突),這將導致解析器識別語法描述的語言的子集。 這可能行不行,在語法不明確的情況下,“子集”實際上就是整個語言,並且默認分辨率會消除歧義。 但是,對於需要更多前瞻性的情況以及某些模棱兩可的情況,默認分辨率將導致無法解析該語言中的某些內容。

為了找出在任何給定的沖突中出了什么問題, .output文件通常為您提供所需的一切。 在您的情況下,您有3個有沖突的狀態-通常,單個狀態中的沖突都是單個相關問題。


state 38
 8 word: TIME .
21 log_entry: entry_prefix TIME . body_statements

此沖突是log_entrybody_statements規則之間的歧義:

log_entry: entry_prefix body_statements
         | entry_prefix TIME body_statements

body_statements可以是一個或多個TIME / DATE / DATA / IDENTIFIER標記的序列,因此當您輸入帶有(例如) entry_prefix TIME DATA的輸入時,它可以是第一個以TIME DATA作為body_statements log_entry規則,也可以是第二個log_entry DATA作為body_statements log_entry規則。

在這種情況下,將有利於第二個規則的默認分辨率(轉移治療TIME為一部分log_statements而不是減少它word是一個部分body_statements ),並會導致一個“子集”這是整個語言-唯一會遺漏的解析是模棱兩可的。 這與某些語言中出現的“懸空”類似,在這種情況下,默認移位可能完全滿足您的要求。

為了消除這種沖突,最簡單的方法就是擺脫log_entry: entry_prefix TIME body_statements規則。 這與默認分辨率有相反的效果-現在TIME將始終被視為BODY的一部分。 問題在於,如果您想以不同的方式對待體內初始TIME的情況,現在沒有單獨的規則可以減少。 如果您需要做一些特別的事情,則可以檢查以TIME開頭的主體的動作。


state 40
6 statement: statement . word
22 body_statements: statement .

這是另一個模棱兩可的問題,這一次是section_body ,它無法分辨一個log_entry在哪里結束而另一個在哪里開始。 section_body由一個或多個log_entries ,每個entry_prefix是一個entry_prefix后跟一個body_statements 如上所述的body_statements可以是一個或多個word令牌,而entry_prefix可以為空。 因此,如果您的section_body只是word標記的序列,則可以將其解析為單個log_entry (不帶entry_prefix )或一系列log_entry規則,每個規則都沒有entry_prefix 缺省情況下, body_statement分辨率的轉換將有利於在減少body_statement之前將盡可能多的標記放入單個statement ,因此將其解析為單個log_entry ,這可能是可以的。

為了消除這種沖突,您需要重構語法。 由於任何的尾部statementlog_entry可能是另一個log_entry沒有entry_prefixstatementbody_statements ,你很可能需要消除的情況下(這是默認的沖突解決一樣)。 假設您已通過刪除第二條log_entry規則解決了先前的沖突,則首先log_entry對log_entry的log_entry以使有問題的情況成為其自己的規則:

log_entry: ERROR_TOK body_statements
         | WARN_TOK body_statements
         | head_desc

initial_log_entry: log_entry
                 | statements

現在更改section_body規則,以便它僅對第一個規則使用分割規則:

section_body: initial_log_entry
            | section_body log_entry

沖突消失了。


state 46
9 word: DATE .
17 time_stamp: statement DATE . TIME

此沖突是一個前瞻性歧義問題-由於DATETIME令牌可能出現在statement ,因此在解析time_stamp它無法判斷該statement在何處結束以及終端DATE / TIME開始。 默認分辨率將導致將任何DATE TIME對視為time_stamp的結尾。 現在,因為time_stamp只出現在年底section_head只是之前section_bodysection_body可以用開始statement ,這可能是罰款為好。


因此,很可能情況是語法中的所有沖突都是可忽略的,甚至這樣做是可取的,因為這比重寫語法來消除它們更簡單。 另一方面,沖突的存在使修改語法變得更加困難,因為在任何時候,您都需要重新檢查所有沖突以確保它們仍然是良性的。


“沖突的默認解決方案”和“狀態中的默認操作”存在一個令人困惑的問題。 這兩個默認值彼此無關-第一個是yacc / bison在構建解析器時做出的決定,第二個是解析器在運行時做出的決定。 因此,當您在輸出文件中有一個狀態時,例如:

state 46

9 word: DATE .
17 time_stamp: statement DATE . TIME

TIME  shift, and go to state 48

TIME      [reduce using rule 9 (word)]
$default  reduce using rule 9 (word)

這是在告訴您,野牛已確定從該狀態開始的可能動作是轉移到狀態48或減少規則9。僅當先行標記為TIME ,才可以執行shift動作,而對於許多先行標記,則可以進行reduce動作。包括時間。 因此,為了最小化表的大小,而不是枚舉reduce動作的所有可能的下一個標記,它只說$default ,這意味着只要沒有先前的動作與lookahead標記匹配,解析器就會執行reduce動作。 $default操作將始終是該狀態中的最后一個操作。

因此,此狀態下的解析器代碼將沿動作列表運行,直到找到與前瞻標記匹配的動作並執行該動作為止。 僅包括TIME [reduce ...]操作,目的是清楚表明在此狀態下存在沖突,並且當先行TIMETIME時,野牛通過禁止操作reduce解決了該沖突。 因此,為此狀態構造的實際操作表將只有一個操作(在令牌TIME ),后跟一個默認操作(在任何令牌上減少)。

請注意,盡管並非所有word在一個word后都是合法的,但它仍然會對任何令牌進行歸約。 這是因為即使下一個令牌是非法的,由於還原操作不會從輸入中讀取它(它仍然是超前的),所以稍后的狀態(可能是多個默認還原操作之后)將看到(並報告)錯誤。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM