使用Grako中的ModelBuilderSemantics避免嵌套对象

时间:2016-10-10 22:15:34

标签: grako

如果您查看下面的语法,您可以看到一个主要规则,表达式,它被解析为更具体的表达式类型。

expression::Expression
=
  or_ex:and_expr {'||' or_ex:and_expr}+
| andex:and_expr
;

and_expr::AndExpression
=
  and_ex:sub_expr {'&&' and_ex:sub_expr}+
| subex:sub_expr
;

sub_expr::SubExpression
=
  {'!!'}* '!(' not_ex:expression ')'
| {'!!'}* '(' sub_ex:expression ')'
| compex:comp_expr
;

comp_expr::CompareExpression
=
  comp:identifier operator:('>=' | '<=' | '==' | '!=' | '>' | '<') comp:identifier
;

identifier::str
=
?/[a-zA-Z][A-Za-z0-9_]*/?
;

下面的test_input解析按预期工作,但我更喜欢用表达式标记表达式中的and_expr元素&#39; @&#39;而不是&#39; andex&#39;。我希望解析的输出只会导致一个CompareExpression对象,它位于Expression对象的not_ex元素中。

!(a == b)

似乎在使用&#39; @&#39;在and_expr元素上的标签,Expression对象中没有显示任何属性!这是一个错误还是故意的?我必须用名称标记所有元素,而不是使用&#39; @&#39;使用ModelBuilderSemantics时标签?

我面临的另一个问题是,如果后来的规则(例如comp_expr)没有关联的类名,则其元素在打印时会出现在字典中,但点符号访问器将失败并且AttributeError,即&#34;属性错误:&#39; dict&#39;对象没有属性&#39; comp&#39;&#34;。有没有办法使用点符号访问器,即使规则没有与它们相关联的类名?

1 个答案:

答案 0 :(得分:0)

我使用的一些标准:

  1. 并非每个规则都必须有关联的Node类。
  2. {}为主表达式的规则适用于返回列表。
  3. 选择|作为主表达式的规则最好返回成功选项返回的内容,即使这通常需要将选项分解为自己的规则。
  4. 优先权很重要。
  5. 等。
  6. 我们的想法是生成的解析模型应该易于使用,特别是 walkers ,最少if-elseisinstance()

    我就是这样做的例子:

    start
        =
        expression $
        ;
    
    
    expression
        =
        | or_expre
        | and_expre
        | sub_expre
        ;
    
    
    or_expre::OrExpression
        =
        operands:'||'.{and_expre}+
        ;
    
    
    and_expr::AndExpression
        =
        operands:'&&'.{sub_expre}+
        ;
    
    
    sub_expr
        =
        | not_expr
        | comp_expre
        | atomic
        ;
    
    
    not_expre::NotExpression
       =
       '!!' ~ sub_expr
       ;
    
    
    comp_expr::CompareExpression
        =
        lef:atomic operator:('>=' | '<=' | '==' | '!=' | '>' | '<') ~ right:atomic
        ;
    
    
    atomic
        =
        | group_expre
        | identifier
        ;
    
    
    group_expr::GroupExpression
        =
        '(' ~ expre:expression ')'
        ;
    
    
    identifier::str
        =
        /[a-zA-Z][A-Za-z0-9_]*/
        ;