Разбирать C-подобные объявления с помощью pyparsing

Я хотел бы проанализировать объявления с помощью pyparsing в C-подобном источнике (код GLSL), чтобы получить список (тип, имя, значение).

Например:

int a[3];
int b=1, c=2.0;
float d = f(z[2], 2) + 3*g(4,a), e;
Point f = {1,2};

Я хотел бы получить что-то вроде:

[ ('int',   'a[3]', ''),
  ('int',   'b',    '1'),
  ('int',   'c',    '2.0'),
  ('float', 'd',    'f(z[2], 2) + 3*g(4,a)'),
  ('float', 'e',    ''),
  ('Point', 'f',    '{1,2}') ]

Я играл с Forward() и operatorPrecedence(), пытаясь разобрать выражение rhs, но подозреваю, что в моем случае это не обязательно.

Пока у меня есть:

IDENTIFIER = Regex('[a-zA-Z_][a-zA-Z_0-9]*')
INTEGER    = Regex('([+-]?(([1-9][0-9]*)|0+))')
EQUAL      = Literal("=").suppress()
SEMI       = Literal(";").suppress()
SIZE       = INTEGER | IDENTIFIER
VARNAME    = IDENTIFIER
TYPENAME   = IDENTIFIER
VARIABLE = Group(VARNAME.setResultsName("name")
                 + Optional(EQUAL + Regex("[^,;]*").setResultsName("value")))
VARIABLES = delimitedList(VARIABLE.setResultsName("variable",listAllMatches=True))
DECLARATION = (TYPENAME.setResultsName("type")
               + VARIABLES.setResultsName("variables", listAllMatches=True) + SEMI)

code = """
float a=1, b=3+f(2), c;
float d=1.0, e;
float f = z(3,4);
"""

for (token, start, end) in DECLARATION.scanString(code):
    for variable in token.variable:
        print token.type, variable.name, variable.value

но последнее выражение (f=z(3,4)) не анализируется из-за ,.


person Nicolas Rougier    schedule 25.02.2015    source источник


Ответы (2)


Существует анализатор структур C на pyparsing wiki, который может дать вам хорошее начало.

person PaulMcG    schedule 25.02.2015
comment
Спасибо, Пол. Это помогло, но у меня все еще есть некоторые ошибки (см. обновленный код здесь) - person Nicolas Rougier; 25.02.2015

Кажется, это работает.

IDENTIFIER       = Word(alphas+"_", alphas+nums+"_" )
INT_DECIMAL      = Regex('([+-]?(([1-9][0-9]*)|0+))')
INT_OCTAL        = Regex('(0[0-7]*)')
INT_HEXADECIMAL  = Regex('(0[xX][0-9a-fA-F]*)')
INTEGER          = INT_HEXADECIMAL | INT_OCTAL | INT_DECIMAL
FLOAT            = Regex('[+-]?(((\d+\.\d*)|(\d*\.\d+))([eE][-+]?\d+)?)|(\d*[eE][+-]?\d+)')
LPAREN, RPAREN   = Literal("(").suppress(), Literal(")").suppress()
LBRACK, RBRACK   = Literal("[").suppress(), Literal("]").suppress()
LBRACE, RBRACE   = Literal("{").suppress(), Literal("}").suppress()
SEMICOLON, COMMA = Literal(";").suppress(), Literal(",").suppress()
EQUAL            = Literal("=").suppress()
SIZE             = INTEGER | IDENTIFIER
VARNAME          = IDENTIFIER
TYPENAME         = IDENTIFIER
OPERATOR         = oneOf("+ - * / [ ] . & ^ ! { }")

PART        = nestedExpr() | nestedExpr('{','}') | IDENTIFIER | INTEGER | FLOAT | OPERATOR
EXPR        = delimitedList(PART, delim=Empty()).setParseAction(keepOriginalText)
VARIABLE    = (VARNAME("name") + Optional(LBRACK + SIZE + RBRACK)("size")
                               + Optional(EQUAL + EXPR)("value"))
VARIABLES   = delimitedList(VARIABLE.setResultsName("variables",listAllMatches=True))
DECLARATION = (TYPENAME("type") + VARIABLES + SEMICOLON)

code = """
int a[3];
int b=1, c=2.0;
float d = f(z[2], 2) + 3*g(4,a), e;
Point f = {1,2};
"""

for (token, start, end) in DECLARATION.scanString(code):
    vtype = token.type
    for variable in token.variables:
        name = variable.name
        size = variable.size
        value = variable.value
        s = "%s / %s" % (vtype,name)
        if size:  s += ' [%s]' % size[0]
        if value: s += ' / %s' % value[0]
        s += ";"
        print s
person Nicolas Rougier    schedule 25.02.2015