Анализирайте 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)


Има С анализатор на структури на 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