簡體   English   中英

yacc停止執行shift && reduce一旦無法從yylex()獲得更多符號

[英]yacc stop doing shift&& reduce once cannot get any more symbol from yylex()

這是我的代碼:

%{
#include<string.h> 
#include "y.tab.h"
#define DEBUG 0
void yyerror(char* s);
void debug(char* string) {
    if (DEBUG) {
        printf(string);
    }
}
%}  
selector   "selector"[0-9]+
positive   "+"
negtive    "-"
contains   "."
before     "->"
or         "||"
and        "&&"
delim      [ /n/t]  
ws         {delim}*
%%  
{selector} { debug("Lex:SELECTOR\n"); yylval.string = yytext; return     SELECTOR; }  
{positive} { debug("Lex:POSITIVE\n"); return POSITIVE; }  
{negtive}  { debug("Lex:NEGTIVE\n"); return NEGTIVE; }  
{contains} { debug("Lex:BELONGS\n"); return CONTAINS; } 
{before}   { debug("Lex:BEFORE\n"); return BEFORE; }  
{or}       { debug("Lex:OR\n"); return OR; }  
{and}      { debug("Lex:AND\n"); return AND; } 
{ws}       ;
.          { debug("Lex Parser Error"); exit(1); }    
%%

.y:
%{
#include <stdio.h>
#define YYDEBUG 0
int yyparse(void);
void yyerror(char* s);
%}

%union {
    char *string;
}

%token <string> SELECTOR 
%token POSITIVE
%token NEGTIVE
%left CONTAINS
%left BEFORE
%token OR
%token AND

%%
logical_expr : assertion { printf("[reduce] L->A\n"); } 
    | logical_expr AND assertion { printf("[reduce] L->L && A\n");}   
    | logical_expr OR assertion { printf("[reduce] L->L || A\n"); }        
;
assertion : POSITIVE prefix_relation { printf("[reduce] A->+P\n"); }
    | NEGTIVE prefix_relation { printf("[reduce] A->-P\n"); }
;
prefix_relation : prefix_relation BEFORE contain_relation { printf("[reduce] P->P->C\n"); }
    | contain_relation { printf("[reduce] P->C\n");;}
;
contain_relation : contain_relation CONTAINS SELECTOR { printf("[reduce] C->C.S[%s]\n", $3); }
    | SELECTOR { printf("[reduce] C->S[%s]\n", $1); }
;
%%
int main()
{
    return yyparse();
}
void yyerror(char* s)
{
    fprintf(stderr,"%s",s);
}
int yywrap()
{
    return 1;
}

我的輸入字符串是: +selector1.selector2||-selector4->selector4

此輸入的分析樹預計為: 預期的分析樹

yacc生成的我的程序輸出如下:

[reduce] C->S[selector1]     // stack: +C
[reduce] C->C.S[selector2]   // stack: +C
[reduce] P->C                // stack: +P
[reduce] A->+P               // stack: A
[reduce] L->A                // stack: L
[reduce] C->S[selector3]     // stack: L||-C
[reduce] P->C                // stack: L||-P
[reduce] C->S[selector4]     // stack: L||-P->C

似乎該程序停止執行shift && reduce一次無法從yylex()獲得更多符號,但是我希望它能夠減少堆棧中剩余的符號,因此L||-P->C ,以便我可以生成整個解析我的代碼中的樹。

我的預期輸出是:

[reduce] C->S[selector1]     // stack: +C
[reduce] C->C.S[selector2]   // stack: +C
[reduce] P->C                // stack: +P
[reduce] A->+P               // stack: A
[reduce] L->A                // stack: L
[reduce] C->S[selector3]     // stack: L||-C
[reduce] P->C                // stack: L||-P
[reduce] C->S[selector4]     // stack: L||-P->C
[reduce] P->P->C             // stack: L||-P
[reduce] A->-P               // stack: L||A
[reduce] L->L||A             // stack: L

掃描儀(flex)的定義存在許多問題。

  1. 您的默認flex規則僅調用exit而不會出現任何錯誤消息(除非定義了DEBUG且非零),因此任何詞法錯誤都將導致程序默默地停止。 在這種情況下,最好調用yyerror並產生可見的錯誤消息。

  2. 正如EJP在注釋中指出的那樣,您的delim定義使用/n/t而不是\\n\\t ,因此它既不會匹配換行符也不會匹配制表符。 換行符也不會與您的默認規則匹配,因此它將落入flex生成的默認規則,該規則僅將不匹配的字符打印到stdout (最好包含%option nodefault ,如果某些輸入與您的規則都不匹配,則會導致flex產生錯誤消息。)

  3. 您的selector規則設置yylval.string = yytext 您不能這樣做,因為yytext指向掃描儀的內部存儲,並且它指向的字符串將在下次調用yylex時進行修改。 如果要將匹配的令牌從掃描儀傳遞到解析器,則必須制作該令牌的副本,然后需要確保在不再需要該字符串時free為其分配的存儲,以避免內存泄漏。

  4. 您需要注意,由bisonyacc生成的解析器通常需要在執行縮減之前讀取前瞻令牌。 因此,在掃描程序返回END令牌之前,不會執行您期望的最后一系列減少操作,只有在讀取文件結尾時才會執行。 因此,如果以交互方式測試解析器,則直到通過鍵入ctrl D (在Unix上)發出文件結束信號,您才會看到最終的縮減。

最后, flexbison都能夠生成調試輸出,該輸出指示匹配的規則(flex)以及一系列的移位,reduce和其他解析器動作(野牛)。 使用這些功能比嘗試實現自己的調試輸出更簡單,更可靠。

暫無
暫無

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

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