使用YACC转换的日期时间解析器减少冲突

时间:2013-02-11 07:14:22

标签: datetime yacc shift-reduce-conflict

我有以下YACC解析器

%start          Start

%token          _DTP_LONG         // Any number; Max upto 4 Digits.  
%token          _DTP_SDF          // 17 Digit number indicating SDF format of Date Time
%token          _DTP_EOS          // end of input
%token          _DTP_MONTH        //Month names e.g Jan,Feb

%token          _DTP_AM            //Is A.M
%token          _DTP_PM            //Is P.M
%%


Start           :   DateTimeShortExpr
                |   DateTimeLongExpr

                |   SDFDateTimeExpr EOS
                |   DateShortExpr EOS
                |   DateLongExpr EOS
                |   MonthExpr EOS
                ;

DateTimeShortExpr   :  DateShortExpr TimeExpr   EOS         {;}
                    |  DateShortExpr AMPMTimeExpr   EOS     {;}
                    ;


DateTimeLongExpr    :  DateLongExpr TimeExpr EOS           {;}
                    |  DateLongExpr AMPMTimeExpr EOS       {;}
                    ;

DateShortExpr   :  Number                                                          {                                       rc = vDateTime.SetDate ((Word) $1,  0,  0);
                                                                    }   


                |  Number Number                                {     rc = vDateTime.SetDate ((Word) $1, (Word) $2,  0); }


                |  Number Number Number                    {     rc = vDateTime.SetDate ((Word) $1, (Word) $2, (Word) $3); }

                ;

DateLongExpr        :   Number AbsMonth                    {     // case : number greater than 31, consider as year
                                                                     if ($1 > 31) {
                                                                        rc = vDateTime.SetDateFunc (1, (Word) $2, (Word) $1);

                                                            }
                                                            // Number is considered as days
                                                            else {
                                                                   rc = vDateTime.SetDateFunc ((Word) $1, (Word) $2,  0);
                                                                 }
                                                            }

                |   Number AbsMonth Number              {rc = vDateTime.SetDateFunc((Word) $1, (Word) $2, (Word) $3);}


                ;                                 

TimeExpr        :   Number                                      {     rc = vDateTime.SetTime ((Word) $1,  0,  0);}

                |   Number Number                               {     rc = vDateTime.SetTime ((Word) $1, (Word) $2,  0); }

                |   Number Number Number                    {     rc = vDateTime.SetTime ((Word) $1, (Word) $2, (Word) $3); }
                ;                                                                                    


AMPMTimeExpr    : TimeExpr _DTP_AM                     {     rc = vDateTime.SetTo24hr(TP_AM)     ; }

                | TimeExpr _DTP_PM                     {     rc = vDateTime.SetTo24hr(TP_PM)     ; }

                | _DTP_AM TimeExpr                     {     rc = vDateTime.SetTo24hr(TP_AM)     ; }

                | _DTP_PM TimeExpr                     {     rc = vDateTime.SetTo24hr(TP_PM)     ; }
                ;


SDFDateTimeExpr   : SDFNumber                          { rc = vDateTime.SetSDF ($1);}

               ;

MonthExpr           : AbsMonth                         {     rc = vDateTime.SetNrmMth ($1);}

                   | AbsMonth Number                   {     rc = vDateTime.Set ($1,$2);}
                ;           

Number              : _DTP_LONG                               {     $$ = $1; }
                ;               

SDFNumber           : _DTP_SDF                              {     $$ = $1; }
                ;               

EOS                 : _DTP_EOS                              {     $$ = $1; }
                ;

AbsMonth            : _DTP_MONTH                            {      $$ = $1;  }
                ;               

%%

它给出了三个移位减少冲突。如何删除它们????

1 个答案:

答案 0 :(得分:1)

转移 - 减少冲突是你的语法所描述的“小语言”所固有的。考虑输入令牌流

_DTP_LONG _DTP_LONG _DTP_LONG EOS

每个_DTP_LONG都可以缩减为Number。但是应该

Number Number Number

缩小为1个数字DateShortExpr后跟2个数字TimeExpr或2个数字DateShortExpr后跟1个数字TimeShortExpr?模棱两可的内在。

如果可能的话,通过添加额外的符号来重新设计您的语言,以区分日期和时间 - 例如,冒号用于设置时间的部分和斜线以设置日期的各个部分。

<强>更新

我认为你不能在这里使用yacc / bison的precedence功能,因为这些令牌难以区分。

当遇到shift/reduce conflict时,你将不得不依赖yacc / bison的默认行为,即转移而不是减少。在输出中考虑这个例子:

+-------------------------     STATE 9     -------------------------+

+ CONFLICTS:

? sft/red (shift & new state 12, rule 11) on _DTP_LONG

+ RULES:

  DateShortExpr :  Number^    (rule 11)
  DateShortExpr :  Number^Number
  DateShortExpr :  Number^Number Number
   DateLongExpr :  Number^AbsMonth
   DateLongExpr :  Number^AbsMonth Number

+ ACTIONS AND GOTOS:

      _DTP_LONG : shift & new state 12
     _DTP_MONTH : shift & new state 13
                : reduce by rule 11

         Number : goto state 26
       AbsMonth : goto state 27

解析器将做的是移动和应用规则12,而不是通过规则11(DateShortExpr : Number)进行缩减。这意味着解析器永远不会将单个Number解释为DateShortExpr;它会永远改变。

依赖于默认行为的一个困难是它可能会随着您对语法的修改而改变。