如何以任何顺序为多个标签声明语法规则?

时间:2012-12-09 11:13:41

标签: grammar bison

我正在尝试为格式化语言编写一个编译器。这种语言有一个start和end属性以及一组文档和文本属性。 第一个是文档本身的信息,第二个是实际文档(标题,段落,列表......通常)。第一个集必须始终遵循start属性,并且必须包含用户可能喜欢的任何顺序的所有属性。

假设我的标记为PROP1,PROP2,PROP3和PROP4,我可以对所有属性使用递归和OR,以便用户可以定义他想要的任何文档属性。

doc_properties
    : /* empty */
    : doc_properties property  
    ;
property
    : PROP1
    : PROP2
    : PROP3
    : PROP4
    ;

但我如何让他定义所有这些并且只有一次。我认为的一种方式(我想避免的简单粗暴的方式)是因为我只有4个文档属性,我可以只做一个或所有可能的组合。我很确定还有另一种方式。有什么帮助吗?

到目前为止我的语法非常简单而且很小

%{ /* C Stuff */ %}

/* union and error stuff and tokens */

%%

source
    : /* empty */  
    | entry_point doc_properties txt_properties exit_point
    ;

entry_point
    : SLASH BLOCK_S LBRACE DOC RBRACE 
    ;

doc_properties 
    : /* This is where my question goes */  
    ;

txt_properties
    : /* empty */  
    ;

exit_point
    : SLASH BLOCK_E LBRACE DOC RBRACE
    ;


%%

int main (int argc, char* argv[])
{
    /* various checks for the arguments and the input output files */

        yyin = fopen(argv[1], "r");
        yyout = fopen(fn, "w");     
        //do{
            yyparse();
        //}while(!feof(yyin));
        fclose(yyin);
        fclose(yyout);

    return 0;
}

void yyerror(const char* str) {
    fprintf(stderr,"syntax error[%d]: %s\n",yylineno, str);
}

同样在一个不相关的注释中,在do-while循环中使用yyparse()或者只使用一次它有什么区别?因为我看到了这两种方式,而do-while循环对我来说更有意义(因为它请求令牌再解析)我不确定函数是重复自身还是其他...

1 个答案:

答案 0 :(得分:3)

有许多语法规则最好通过语义检查而不是语法本身来强制执行。例如,在类似C语言中,break构造只能出现在循环(和开关)中,但是接受它就像任何常规语句一样简单,而稍后,在语义分析通过,拒绝对break的无效使用。

您可以使用类似的模式:接受PROP的任意组合,然后拒绝那些不符合您的约束的组合。当然,您也可以在解析时执行此操作,在适当的时候使用YYERROR引发错误。

对于你的第二个问题,yyparse只能被调用一次,但当然它负责反复调用扫描器(yylex)。请注意,Bison提供“推送解析器”,其中负责反复调用yylex,并将其结果传递给yyparse(反复也是如此)。有关详细信息,请参阅http://www.gnu.org/software/bison/manual/bison.html#Push-Decl