2016-07-08 1 views
2

Je développe un analyseur pour le langage DOT et j'ai des problèmes avec les instructions "subgraph".Erreur de correspondance la plus longue de pypars suspectée

Je n'ai aucun problème pour que mon expression d'analyse SUBGRAPH fonctionne correctement (voir le fragment ci-dessous). Cependant, lorsque je l'ajoute comme alternative dans STMT, elle ne correspond pas.

Test simple:

test = '''subgraph cluster01 { n003 ; n004 ; }''' 
FRAG_1 = SUBGRAPH + StringEnd() 
FRAG_2 = STMT + StringEnd() 

res1 = FRAG_1.parseString(test) # OK 
res2 = FRAG_2.parseString(test) # ParseException - 

Erreur:

subgraph cluster01 { n003 ; n004 ; } 
     ^
ERROR: Expected end of text (at char 9), (line:1, col:10) 

Je suspect le problème implique mon expression Stmt - qu'il correspond cupides le mot-clé "de subgraph" comme NODE_STMT Plutôt que de faire une correspondance en SUBGRAPH, je m'attends à ce que l'utilisation d'une expression "Or" ("^") permette à l'algorithme de correspondance le plus long de choisir SUBGR APH sur NODE_STMT. Ou ça pourrait être autre chose.

Ma grammaire partielle est ci-dessous:

Grammaire Fragment:

LCURL = Literal("{").suppress() 
RCURL = Literal("}").suppress() 
STMTSEP = Literal(";").suppress() 
ID = Word(alphas, alphanums + "_") 
SUBGRAPH_KW = Keyword("subgraph", caseless=True) 
SUBGRAPH = Forward("SUBGRAPH") 

NODE_ID = ID("NODE_ID") 
NODE_STMT = NODE_ID("NODE") 

STMT = NODE_STMT("NODE")^SUBGRAPH("SUBGRAPH") 
STMT_LIST = ZeroOrMore(STMT("STMT") + Optional(STMTSEP)) 

SUBGRAPH << Group(SUBGRAPH_KW + ID("SUBGRAPHNAME")) + Group(LCURL + STMT_LIST + RCURL) 

Répondre

1

C'est parce que vous créez une copie de l'objet SUBGRAPH dans cette ligne:

STMT = NODE_STMT("NODE")^SUBGRAPH("SUBGRAPH") 

L'appel setResultsName(), que la syntaxe d'appel est comme hortcut pour, creates a copy of the ParserElement object.

Ceci est un problème car SUBGRAPH est un objet Forward, et à ce stade dans le code, il n'a pas encore été entièrement défini.

Vous ne devriez vraiment pas définir des noms pour tout, partout, tout le temps! Faites-le quand et où vous en avez réellement besoin, et gardez à l'esprit qu'il crée des copies des objets ParserElement.

+0

Brillant! Je vais devoir penser à ce que l'utilisation correcte de ParserElement.setResultName() est réellement si ... – SMagrath

+1

Bonne prise!Je n'ai pas vu ce problème particulier surgir sous cette forme particulière avant (nom de résultats + Forward), certainement besoin d'ajouter à ma liste de getchas pyparsing. – PaulMcG

0

En général, je recommande la tenue de rabais sur l'attribution des noms de résultats jusqu'à ce que les expressions sont assemblés en une expression de niveau supérieur, comme celui-ci:

intnum = Word(nums).setParseAction(lambda t: int(t[0])) 
realnum = Combine(Word(nums) + '.' + Word(nums)).setParseAction(lambda t: float(t[0])) 
hostname = Word(alphas, alphanums+'-') 
timestamp = Regex(r'\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d') 
statslogentry = (timestamp('timestamp') + hostname('hostname') + 
       'CPU:' + realnum('cpu') + 
       'DISK_IO:' + intnum('disk_io') + 
       'NETWORK_IO:' + intnum('network_io')) 

Cependant, lors de l'utilisation Forward cela peut se retourner contre vous, comme le cas ici. Une erreur spécifique dans le code de l'OP est

SUBGRAPH = Forward("SUBGRAPH") 

Je pense que l'OP tente d'utiliser le nom de raccourci des résultats, mais est en fait de créer un Forward avec une teneur en Literal("SUBGRAPH"). La modification de ce à

SUBGRAPH = Forward()("SUBGRAPH") 

et en supprimant le nom des résultats de l'expression Or résoudrait le problème d'origine. Mais je pense toujours que cela tombe un peu dans la catégorie "gotcha".

+0

Merci Paul. C'est un bon conseil. Aussi, merci beaucoup pour cet excellent outil ... – SMagrath