Parsing di script che utilizzano parentesi graffe

7

Per avere un'idea di quello che sto facendo, sto scrivendo un parser python che analizzerà i file di testo .x di directx.

Il problema che ho a che fare con come i file sono formattati. Anche se sto scrivendo in Python, sto cercando algoritmi generali per affrontare questo tipo di analisi.

I file

.x definiscono i dati utilizzando i modelli. Il formato di un modello è

template_name {
   [some_data]
}

L'obiettivo che ho è quello di analizzare il file riga per riga e ogni volta che trovo un modello, mi occuperò di conseguenza.

Il mio approccio iniziale era di verificare se una linea contiene una parentesi graffa di apertura o chiusura. Se si tratta di una parentesi graffa aperta, verificherò il nome del modello.

Ora il problema è che la parentesi aperta non deve necessariamente comparire sulla stessa riga del nome del modello. Potrebbe anche essere

template_name
{
   [some_data]
}

Quindi, se dovessi usare il mio criterio "Esiste una parentesi aperta", non funzionerà per tutti i file che utilizzano il secondo formato.

Molte lingue usano anche parentesi graffe (anche se non sono sicuro che le persone possano analizzare personalmente gli script), quindi mi chiedevo se qualcuno sa come ottenere con precisione il nome del modello (o in alcune altre lingue, potrebbe anche essere un nome di funzione, anche se non ci sono parole chiave da cercare)

    
posta That Umbrella Guy 28.06.2011 - 17:34
fonte

3 risposte

6

Se stai usando Python, dovresti usare PyParsing , l'ho usato con grande successo da un anno a questa parte.

The pyparsing module is an alternative approach to creating and executing simple grammars, vs. the traditional lex/yacc approach, or the use of regular expressions. The pyparsing module provides a library of classes that client code uses to construct the grammar directly in Python code...

    
risposta data 28.06.2011 - 18:07
fonte
5

Per favore, non scrivi ancora-un altro pessimo parser. Dai un'occhiata a un lexer / parser (ad es. PLY ) e fallo correttamente. Sarà meno doloroso per te e molto meno doloroso per i tuoi utenti.

    
risposta data 28.06.2011 - 17:42
fonte
5

Ecco come apparirà una soluzione di pypars:

from pyparsing import *

LBRACE,RBRACE,LBRACK,RBRACK,SEMI = map(Suppress,'{}[];')

TEMPLATE = Keyword("template")
ident = Word(alphas, alphanums+"_")
uuid = Regex(r'<[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}>')
integer = Word(nums)
arrayDim = LBRACK + (integer|ident) + RBRACK

baseType = oneOf("WORD DWORD FLOAT DOUBLE CHAR UCHAR BYTE STRING CSTRING UNICODE")
ARRAY = Keyword("array")
typeRef = baseType | ident

memberDefn = Group(ARRAY + typeRef("type") + ident("name") + 
                       ZeroOrMore(arrayDim)("dims") + SEMI |
                   typeRef("type") + ident("name") + SEMI)
templateDefn = (TEMPLATE + ident("name") + LBRACE + 
    Optional(uuid)("uuid") +
    ZeroOrMore(memberDefn)("members") + 
    RBRACE)


sample = """
some stuff...

template Mesh {
<3D82AB44-62DA-11cf-AB39-0020AF71E433>
DWORD nVertices;
array Vector vertices[nVertices];
DWORD nFaces;
array MeshFace faces[nFaces][4];
}

more stuff...
"""

for tplt in templateDefn.searchString(sample):
    print tplt.dump()
    for mbr in tplt.members:
        print mbr.dump(indent='  ')
    print tplt.name, tplt.uuid

stampe:

['template', 'Mesh', '<3D82AB44-62DA-11cf-AB39-0020AF71E433>', ['DWORD', 'nVertices'], ['array', 'Vector', 'vertices', 'nVertices'], ['DWORD', 'nFaces'], ['array', 'MeshFace', 'faces', 'nFaces', '4']]
- members: [['DWORD', 'nVertices'], ['array', 'Vector', 'vertices', 'nVertices'], ['DWORD', 'nFaces'], ['array', 'MeshFace', 'faces', 'nFaces', '4']]
- name: Mesh
- uuid: <3D82AB44-62DA-11cf-AB39-0020AF71E433>
  ['DWORD', 'nVertices']
  - name: nVertices
  - type: DWORD
  ['array', 'Vector', 'vertices', 'nVertices']
  - dims: ['nVertices']
  - name: vertices
  - type: Vector
  ['DWORD', 'nFaces']
  - name: nFaces
  - type: DWORD
  ['array', 'MeshFace', 'faces', 'nFaces', '4']
  - dims: ['nFaces', '4']
  - name: faces
  - type: MeshFace
Mesh <3D82AB44-62DA-11cf-AB39-0020AF71E433>
    
risposta data 29.06.2011 - 07:16
fonte

Leggi altre domande sui tag