python - 使用 Python 和 pyparsing 解析 Visual Basic 函数的参数列表

标签 python vba pyparsing

我正在尝试使用 pyparsing 解析 Visual Basic (VBA) 函数声明将它们转换为 Python 语法。

通常的 VBA 函数头不是一个大问题,对我来说工作得很好。但我对参数列表有困难:

Public Function MyFuncName(first As Integer, Second As String) As Integer

参数由逗号分隔的零到多个部分组成,例如:

VarName
VarName As VarType
Optional VarName As VarType = InitValue
ByVal VarName As VarType

其中“Optional”、“ByVal”和“ByRef”以及类型声明都是完全可选的。

我的想法是从原始行中提取完整的参数列表

allparams = Regex('[^)]*').setResultsName('params')

然后分别解析它们。这匹配单个参数:

variablename = Word(alphas + '_', alphanums + '_')
typename = variablename.setResultsName('type')
default_value = Word(alphanums)
optional_term = oneOf('Optional', True)
byval_term = oneOf('ByRef ByVal', True)

paramsparser = Optional(optional_term) \
    +Optional(byval_term) \
    +variablename.setResultsName('pname', True) \
    +Optional('As' + typename) \
    +Optional('=' + default_value)

但即使使用 delimitedList(paramsparser) 我也只能得到其中的第一个。

AssertionError: 'def test(one):\n\tpass' != 'def test(one, two):\n\tpass'
- def test(one):
+ def test(one, two):
?             +++++

您有什么想法可以实现这一点吗?

最佳答案

我几乎按照您发布的方式使用了您的代码,并将其包装在 delimitedList 中并获取了两个参数:

paramsparser = Optional(optional_term) \
    +Optional(byval_term) \
    +variablename.setResultsName('pname', True) \
    +Optional('As' + typename) \
    +Optional('=' + default_value)

parser = "(" + delimitedList(paramsparser) + ")"

parser.runTests("""\
    (one, two)
    (ByRef one As Int = 1, Optional ByVal two As Char)
""")

打印:

(one, two)
['(', 'one', 'two', ')']
- pname: ['one', 'two']

(ByRef one As Int = 1, Optional ByVal two As Char)
['(', 'ByRef', 'one', 'As', 'Int', '=', '1', 'Optional', 'ByVal', 'two', 'As', 'Char', ')']
- pname: ['one', 'two']
- type: 'Char'

但是由于每个参数有很多字段,我建议为每个字段提供一个单独的结果名称并包装在 Group 中,以防止参数相互干扰。这是我对您的解析器的修改(非常有帮助,您为不同的可选声明字段发布了各种表单):

from pyparsing import (Word, alphas, alphanums, quotedString, Keyword, Group, Optional, oneOf, delimitedList,
                       Suppress, pyparsing_common as ppc)

LPAR, RPAR, EQ = map(Suppress, "()=")
OPTIONAL, BYREF, BYVAL, AS, FUNCTION = map(Keyword, "Optional ByRef ByVal As Function".split())

# think abstract for expression names, like 'identifier' not 'variablename'; then
# you can use identifier for the variable name, the function name, as a possible
# var type, etc.
identifier = Word(alphas + "_", alphanums + "_")
rvalue = ppc.number() | quotedString() | identifier()
type_expr = identifier()

# add results names when assembling in groups
param_expr = Group(
    Optional(OPTIONAL("optional"))
    + Optional(BYREF("byref") | BYVAL("byval"))
    + identifier("pname")
    + Optional(AS + type_expr("ptype"))
    + Optional(EQ + rvalue("default"))
)

然后,我不会使用正则表达式来获取参数,然后在单独的步骤中重新解析,而是将其包含在整个函数表达式定义中:

protection = oneOf("Public Private", asKeyword=True)
func_expr = (
    protection("protection")
    + FUNCTION
    + identifier("fname")
    + Group(LPAR + delimitedList(param_expr) + RPAR)("parameters")
    + Optional(AS + type_expr("return_type"))
)

tests = """
Public Function MyFuncName(first As Integer, Second As String) As Integer
"""
func_expr.runTests(tests)

打印:

Public Function MyFuncName(first As Integer, Second As String) As Integer
['Public', 'Function', 'MyFuncName', [['first', 'As', 'Integer'], ['Second', 'As', 'String']], 'As', 'Integer']
- fname: 'MyFuncName'
- parameters: [['first', 'As', 'Integer'], ['Second', 'As', 'String']]
  [0]:
    ['first', 'As', 'Integer']
    - pname: 'first'
    - ptype: 'Integer'
  [1]:
    ['Second', 'As', 'String']
    - pname: 'Second'
    - ptype: 'String'
- protection: 'Public'
- return_type: 'Integer'

关于python - 使用 Python 和 pyparsing 解析 Visual Basic 函数的参数列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59101513/

相关文章:

Python HackerRank Bonetrousle 代码超时

python - IPython Notebook 打不开;抛出 "Symbol Not Found"错误

python - 使用 pyparsing 解析 <attribute value> 对时出错

python - PyParsing 不同的字符串长度

python - 创建围绕零镜像的数字列表(python)

python - 无需浏览器的导航实用程序,重量轻且防故障

excel - 如何命名 QueryTable 使用的连接

excel - 检查工作表是否存在,如果不存在则创建 -VBA

excel - 在 workbook_open 上添加工作表

python - 在 pyparsing 中强制在标记之间添加空格