0

我正在尝试为一种格式化语言编写一个编译器。这种语言有一个开始和结束属性以及一组文档和文本属性。第一个只是文档本身的信息,而第二个是实际文档(标题,段落,列表......通常)。第一个集合必须始终遵循 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 循环对我来说更有意义(因为它请求一个令牌解析然后再次)我不确定该函数是否重复自身或什么......

4

1 回答 1

3

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

您可以使用类似的模式:接受 的任何组合PROP,然后拒绝那些不尊重您的约束的组合。当然,你也可以在解析时这样做,YYERROR在适当的时候使用来引发错误。

对于您的第二个问题,yyparse只调用一次,但当然它负责yylex重复调用扫描仪()。请注意,Bison 提供“push-parsers”,负责yylex重复调用,并将其结果传递给yyparse(也重复)。有关详细信息,请参阅http://www.gnu.org/software/bison/manual/bison.html#Push-Decl 。

于 2012-12-09T13:58:36.620 回答