1

我有一个 TatSu 语法,我正在解析算术表达式,例如SignalGroup {ABUS='A3 + A2 + A1 + A0';}.

相关语法:

#--------------------------------------------- SIGNAL GROUPS BLOCK -----------------------------------------------------
signal_groups_block::SignalGroups
    =
    'SignalGroups' ~ [id:identifier] '{' ~ objs:{signal_group | annotation | udb} '}'
    ;
signal_group::SignalGroup
    =
    id:identifier '=' expr:signal_reference_expr ( ';' |
                                                   ('{' ~ attr:{signal_statement | annotation |udb} '}') )
    ;
signal_reference_expr
    =
    signal_name_array_opt
    | "'" ~ exprs:signal_reference_expr_items "'"
    ;
signal_reference_expr_items
    =
    left:signal_reference_expr_items op:'+' ~ right:signal_reference_expr_item
    | left:signal_reference_expr_items op:'-' ~ right:signal_reference_expr_item
    | left:signal_reference_expr_item
    ;
signal_reference_expr_item
    =
    '(' ~ @:signal_reference_expr_items ')'
    | signal_name_array_opt
    ;
signal_name_array_opt
    =
    id:identifier ['[' ~ msb:integer ['..' ~ lsb:integer] ']']
    ;

AST 输出:

{
  "objs": [
    {
      "__class__": "SignalGroup",
      "expr": {
        "exprs": {
          "left": {
            "left": {
              "left": {
                "left": {
                  "id": "A3",
                  "lsb": null,
                  "msb": null
                },
                "op": null,
                "right": null
              },
              "op": "+",
              "right": {
                "id": "A2",
                "lsb": null,
                "msb": null
              }
            },
            "op": "+",
            "right": {
              "id": "A1",
              "lsb": null,
              "msb": null
            }
          },
          "op": "+",
          "right": {
            "id": "A0",
            "lsb": null,
            "msb": null
          }
        }
      },
      "attr": null,
      "id": "ABUS"
    }
  ],
  "id": null
}

我想对此规则进行一些语义验证。也就是说,检查信号 A3-A0 是否已在其他(信号)块中声明。如果未声明,则引发错误。在解析另一个(信号)块时,我保留了所有信号的命名(符号)表以供查找。我想知道在语义动作代码中“走”这样一个 AST 的最佳步行是什么,因为如果我的表达式包含 200 个信号(即 A0 + A1 + .. A199),它可能非常深。现在,我只有一个像这样的存根函数:

class STILSemantics(ModelBuilderSemantics):

    ....

    def signal_groups_block(self, ast, node):
    """Signal groups block."""

      log.info('Parse %s block', node)
      print('got here')
      from tatsu.util import asjsons
      print(asjsons(ast))

      # TODO: HOW TO WALK THE AST HERE????

      return ast

我检查了 TatSu 文档,其中有一个部分,Walking Models但似乎只有在构建完整模型 AST之后。也许我错了。在构建整个(顶级)模型时,有没有办法在语义验证规则中有效地遍历 signal_groups_block 的 AST?

参考:https ://tatsu.readthedocs.io/en/stable/models.html#walking-models

4

1 回答 1

2

要在解析期间检查预定义的标识符,您需要一个符号表

您将符号添加到定义它们的语法子句的语义表中,并查阅使用它们的语法子句的语义中的符号表。

因为 TatSu 保留了源输入的完整信息,所以在解析后使用walker检查这些语义可能更容易。报告的错误可以精确到行列号,用户通常不介意先报告语法错误,然后再报告语义错误,因为 TatSu 解析器通常会在第一个错误时停止(在 Tatsu 中支持解析恢复,但它没有记录)。

解析阶段的符号表在其中一个标记可能是或可能不是取决于上下文的关键字的语言中是必需的(是的,PEG 可以通过帮助语义动作处理一些上下文敏感的情况)。

于 2020-02-14T00:36:15.563 回答