野牛 - 根据语法期望处理expr

时间:2017-03-13 07:52:55

标签: bison yacc

我正在开发一种语法,我使用常量,变量和数组。数组可以像name[]一样,也可以像name一样。 每个语句都使用expr或数组之类的参数。 在解析时,没有[]的变量和数组名称之间没有区别。

array_empty:
                        args_variable '[' ']';

args_array:
                        array_empty {
                            //special command to put array on app stack
                        }
                        | args_variable {
                            //special command to put array on app stack
                        }
args_variable:
                        MYVARIABLE {
                            //Store variable into a variable table
                        }
                        | '(' args_variable ')'
                        ;
args_Ae:
                        expr ',' args_array
            | '(' args_Ae ')';
expr:                   ....

..................

appsomestmt:  APPSOME expr {
                        //do something - one argument
                        }
                        | APPSOME args_Ae {
                        //do something else - two arguments
                        }
                        ;

语句可以有多种语法,如:

APPSOME expr
APPSOME array, expr

但是如果我在我的应用程序中使用语句APPSOME variable,则将variable减少到args_variable,然后减少到args_array,即使只有一个参数。 我希望该程序检测到该语句只有一个参数并使用第一个语法APPSOME expr。只有当语句有APPSOME array, expr这样的2个参数时,我才想使用第二种语法APPSOME array, expr

我该怎么做?请记住,数组在Mid-Rule 中有一些 Actions,可以将数组放在app堆栈上。 那么,我如何根据语法期望强制Bison将变量视为变量/数组?

修改

%{
%}

%token APPSOME1 APPSOME2
%token <number> APPVARIABLE 

%left '-' '+'
%left '*' '/'
%left '^'

%%

program:        programline programnewline program
                | programline
                ;

programnewline:
                '\n' {
                    //some code
                }
                ;

programline:    compoundstmt
            | /* empty */
            ;

compoundstmt:
                        compoundstmt ':' statement
                        | statement
            ;

array_empty:
                        args_variable '[' ']';

// Array Variable Data
args_array:
                        array_empty {
                            //tell interpretor that next is a array
                        }
                        | args_variable {
                            //tell interpretor that next is a array
                        }
                        ;

args_variable:
                        APPVARIABLE {
                                //put variable into table
                        }
                        | '(' args_variable ')'
                        ;

/* multiple arguments */

args_ee:
                        expr ',' expr
            | '(' args_ee ')';
args_ae:
                        args_array ',' expr
            |'(' args_ae ')';
args_aee:
                        args_array ',' expr ',' expr
            |'(' args_ae ')';

/* list of statements */

statement:
            app1stmt
                        | app2stmt

            ;


app1stmt:  APPSOME1 expr {
                            //code
                        }
                        | APPSOME1 args_ae {
                            //code
                        }
                        ;

app2stmt:  APPSOME2 args_ee {
                            //code
                        }
                        | APPSOME2 args_aee {
                            //code
                        }
                        ;

expr:
            '(' expr ')'
            | expr '+' expr {
                //code
            }
            | args_variable {
                                //variable
            }
            | expr '-' expr {
                //code
            }
            | expr '*' expr {
                //code
            }
            | expr '/' expr {
                //code
            }
            | expr '^' expr {
                //code
            }
            ;

%%

1 个答案:

答案 0 :(得分:1)

该语法存在一些问题。

APPSOME1确实存在问题,需要exprarray, expr。一旦看到逗号,就可以选择选择哪个选项(但请参阅下面有关括号的内容)。但是,APPSOME2无效:

APPSOME2: expr ',' expr
        | array ',' expr ',' expr

这里,在遇到第二个逗号之前不可能消除歧义,并且这可能与解析器需要做出决定的点(在第一个逗号之前)之间任意距离

另一个复杂因素是

之间产生的歧义
args_variable
    : APPVARIABLE
    | '(' args_variable ')'
expr: args_variable
    | '(' expr ')'

当解析器看到)时,它无法知道上一次生成是否适用,因为这取决于,是否跟在带括号的表达式之后。

就个人而言,我只是通过不允许数组参数括起来来解决这个问题,但你也可以通过引入一个&#34;括号参数来解决这个问题&#34;非终端,允许决定推迟到最后一个闭括号之后。这意味着,如果你有

APPSOME1 (((ARRAYNAME))), expr

您可以避免在ARRAYNAME上执行必要的操作,直到您点击最后一个右括号,这似乎应该是这种情况。

APPSOME2问题没有这么简单的解决方法。

通常情况下,我建议使用GLR解析器来解决这个问题。由于语法实际上并不模糊,据我所知,GLR算法应该能够处理语法对于任何k都不是LR(k)的事实。但是你需要仔细考虑解析器动作的处理;在由bison构建的GLR解析器中,在解析器知道将需要哪些操作之前不会处理操作,这意味着在读取了更多的令牌之后可能不会执行操作。通常情况并不重要,但如果您将符号表信息反馈到您的词汇扫描仪中,则无法正常工作。

当然,总是有可能改变语法,使arraynames的使用不那么模糊。例如,您可以使用如下语法:

APPSOME1 expr
APPSOME1 array expr
APPSOME2 expr, expr
APPSOME2 array expr, expr

其中数组引用根本不使用逗号。这可能对您的用户来说有点微妙,但它也可能使代码更容易阅读,因为它提供了关于命令名称之后的第一件事是否用作数组的视觉提示。