词中的反斜杠冲突与句法分析中的换行符

2024-09-27 18:23:18 发布

您现在位置:Python中文网/ 问答频道 /正文

我很难理解允许在参数名中使用“\”的语法(例如.net\<;8>;)。但是,“\”也用作续行(参见示例2)。Ex1工作正常,但是linebreakidentifier变量之间存在冲突

示例1:正在工作(netlist.sp)

subckt INVERTER A Z gnd gnds vdd vdds
M1 (Z A vdd vdds) pmos w=0.4 l=0.1
M2 (Z A gnd gnds) nmos w=0.2 l=0.1
ends INVERTER

I1 (net1 net2 0 gnds! vdd! vdds!) INVERTER

subckt INVERTER_2 A Z gnd gnds vdd vdds
M1 (Z A vdd vdds) pmos w=0.4 l=0.1
M2 (Z A gnd gnds) nmos w=0.2 l=0.1
ends INVERTER_2

I2 (net\<8\> net2 0 gnds! vdd! vdds!) INVERTER_2

I3 (net1 net2 0 gnds! vdd! vdds!) INVERTER_2

例2:不工作(netlist2.sp)

subckt INVERTER A Z gnd gnds vdd vdds
M1 (Z A vdd vdds) pmos w=0.4 l=0.1
M2 (Z A gnd gnds) nmos w=0.2 l=0.1
ends INVERTER

I1 (net1 net2 0 gnds! vdd! vdds!) INVERTER

subckt INVERTER_2 A Z gnd gnds \
                  vdd vdds
M1 (Z A vdd vdds) pmos w=0.4 l=0.1
M2 (Z A gnd gnds) nmos w=0.2 l=0.1
ends INVERTER_2

I2 (net\<8\> net2 0 gnds! vdd! vdds!) INVERTER_2

I3 (net1 net2 0 gnds! vdd! vdds!) INVERTER_2

代码

import pyparsing as pp
import json

EOL = pp.LineEnd().suppress() # end of line
linebreak = pp.Suppress(pp.Keyword('\\') + pp.LineEnd())
identifier = pp.Word(pp.alphanums + '_!<>\\')
number = pp.pyparsing_common.number
net = identifier
instref = identifier
instname = identifier
subcktname = identifier
subcktname_end = pp.Keyword("ends").suppress()
comment = pp.Suppress("//" + pp.SkipTo(pp.LineEnd()))
expression = pp.Word(pp.alphanums + '._*+-/()')

input_file = open(netlist.sp,'r')
file_string = input_file.read()
input_file.close()

for t, s, e in parse_netlist().scanString(file_string):
    print(json.dumps(t.asDict()['netlist'], indent=2))

def parse_netlist():
        pp.ParserElement.setDefaultWhitespaceChars(' \t')

        nets = (pp.Optional(pp.Suppress('('))
                + pp.OneOrMore(net('net') | linebreak)
                + pp.Optional(pp.Suppress(')'))
               )

        inst_param_value = expression('expression')

        inst_parameter = pp.Dict(pp.Group(identifier('param_name')
                                  + pp.Suppress("=")
                                  + inst_param_value('param_value')
                                 ))

        parameters = pp.Group(pp.OneOrMore(inst_parameter | linebreak)
                             ).setResultsName('parameters')

        instance = pp.Dict(pp.Group(instname('inst_name')
                            + nets('nets')
                            + instref('reference')
                            + pp.Optional(parameters)
                            + EOL
                           )).setResultsName('instance', listAllMatches=True)

        subckt_core = pp.Group(pp.ZeroOrMore(instance | EOL | comment)
                              ).setResultsName('subckt_core', listAllMatches=True)

        subckt = pp.Group(pp.Keyword("subckt").suppress()
                          + subcktname('subckt_name')
                          + nets('nets')
                          + EOL
                          + subckt_core
                          + subcktname_end
                          + pp.matchPreviousExpr(subcktname).suppress()
                          + EOL
                         ).setResultsName('subcircuit', listAllMatches=True)

        netlist = pp.OneOrMore(subckt
                               | instance
                               | comment('comment')
                               | EOL
                              ).setResultsName('netlist') + pp.StringEnd()

        return netlist

输出Ex1

[
  {
    "subckt_name": "INVERTER",
    "net": "vdds",
    "nets": [
      "A",
      "Z",
      "gnd",
      "gnds",
      "vdd",
      "vdds"
    ],
    "subckt_core": [
      {
        "instance": [
          {
            "M1": {
              "inst_name": "M1",
              "net": "vdds",
              "nets": [
                "Z",
                "A",
                "vdd",
                "vdds"
              ],
              "reference": "pmos",
              "parameters": {
                "w": "0.4",
                "l": "0.1"
              }
            }
          },
          {
            "M2": {
              "inst_name": "M2",
              "net": "gnds",
              "nets": [
                "Z",
                "A",
                "gnd",
                "gnds"
              ],
              "reference": "nmos",
              "parameters": {
                "w": "0.2",
                "l": "0.1"
              }
            }
          }
        ]
      }
    ]
  },
  {
    "I1": {
      "inst_name": "I1",
      "net": "vdds!",
      "nets": [
        "net1",
        "net2",
        "0",
        "gnds!",
        "vdd!",
        "vdds!"
      ],
      "reference": "INVERTER",
      "parameters": []
    }
  },
  {
    "subckt_name": "INVERTER_2",
    "net": "vdds",
    "nets": [
      "A",
      "Z",
      "gnd",
      "gnds",
      "vdd",
      "vdds"
    ],
    "subckt_core": [
      {
        "instance": [
          {
            "M1": {
              "inst_name": "M1",
              "net": "vdds",
              "nets": [
                "Z",
                "A",
                "vdd",
                "vdds"
              ],
              "reference": "pmos",
              "parameters": {
                "w": "0.4",
                "l": "0.1"
              }
            }
          },
          {
            "M2": {
              "inst_name": "M2",
              "net": "gnds",
              "nets": [
                "Z",
                "A",
                "gnd",
                "gnds"
              ],
              "reference": "nmos",
              "parameters": {
                "w": "0.2",
                "l": "0.1"
              }
            }
          }
        ]
      }
    ]
  },
  {
    "I2": {
      "inst_name": "I2",
      "net": "vdds!",
      "nets": [
        "net\\<8\\>",
        "net2",
        "0",
        "gnds!",
        "vdd!",
        "vdds!"
      ],
      "reference": "INVERTER_2",
      "parameters": []
    }
  },
  {
    "I3": {
      "inst_name": "I3",
      "net": "vdds!",
      "nets": [
        "net1",
        "net2",
        "0",
        "gnds!",
        "vdd!",
        "vdds!"
      ],
      "reference": "INVERTER_2",
      "parameters": []
    }
  }
]

Ex2的输出

[
  {
    "I2": {
      "inst_name": "I2",
      "net": "vdds!",
      "nets": [
        "INST_IN\\<8\\>",
        "net2",
        "0",
        "gnds!",
        "vdd!",
        "vdds!"
      ],
      "reference": "INVERTER2",
      "parameters": []
    }
  },
  {
    "I3": {
      "inst_name": "I3",
      "net": "vdds!",
      "nets": [
        "net1",
        "net2",
        "0",
        "gnds!",
        "vdd!",
        "vdds!"
      ],
      "reference": "INVERTER3",
      "parameters": []
    }
  }
]

语法:

格式化子电路定义:

subckt SubcircuitName [(] node1 ... nodeN [)]
[ parameters name1=value1 ... [nameN=valueN]]
.
.
.
instance, model, ic, or nodeset statements—or
further subcircuit definitions
.
.
.
ends [SubcircuitName]

格式化实例语句:

name [(]node1 ... nodeN[)] master [[param1=value1] ...[paramN=valueN]]

Tags: namenetppparametersreferencevddnetlistgnd
1条回答
网友
1楼 · 发布于 2024-09-27 18:23:18

Word是pyparsing中最贪婪和最具攻击性的重复类型之一。所以你的两个表情:

linebreak = pp.Suppress(pp.Keyword('\\') + pp.LineEnd())
identifier = pp.Word(pp.alphanums + '_!<>\\')

会有冲突。一旦标识符开始扫描匹配的字符,它就不会向前看下一个表达式是否应该停止

为了区分标识符中的“\”和作为延续符的“\”之间的区别,可以从linebreak开始。接下来,我们需要从标识符字中的字符中删除“\”:

identifier = pp.Word(pp.alphanums + '_!<>')

要在标识符中添加回“\”,我们需要更具体一些。不仅仅是任何“\”都可以,我们只需要不是换行符的“\”(也就是说,那些不在行尾的换行符)。我们可以用消极的态度来做。在接受反斜杠之前,首先确保它不是换行反斜杠:

backslash_that_is_not_a_linebreak = ~linebreak + '\\'

现在identifier将是一个或多个单词项的集合,可以是上面定义的identifier单词,也可以是不是换行符的反斜杠

identifier_word = pp.Word(pp.alphanums + '_!<>')
identifier = pp.OneOrMore(identifier_word | backslash_that_is_not_a_linebreak)

这让我们很接近,但如果您使用此标识符来解析“net\<;8>;“,您将得到:

['net', '\\', '<8', '\\', '>']

如果在pyparsingCombine中包装标识符,那么所有这些都应该可以正常工作:

identifier = pp.Combine(pp.OneOrMore(identifier_word | backslash_that_is_not_a_linebreak))

print(identifier.parseString(r"net\<8\>"))

提供:

['net\\<8\\>']

编辑: 总而言之,以下是进行此更改所需的mod:

backslash_that_is_not_a_linebreak = ~linebreak + '\\'
identifier_word = pp.Word(pp.alphanums + '_!<>')
identifier = pp.Combine(pp.OneOrMore(identifier_word | backslash_that_is_not_a_linebreak))

编辑2: 在方法parse_netlist中声明的这些行需要在导入pyparsing之后位于模块的顶部。否则,像linebreak这样的所有表达式都将使用默认的空白字符,包括\n

ws = ' \t'
pp.ParserElement.setDefaultWhitespaceChars(ws)

如果没有它们,nets的表达式将读取超过您的subckt的第一行中的行尾,并将“M2:作为另一个网而不是作为subckt_core中第一个instance的标识符

不知道为什么你的语法分析器会这样分解,最好把所有的位放在一起

相关问题 更多 >

    热门问题