2016-10-03 8 views
1

J'essaye d'écrire un analyseur pour des configurations de Cisco IOS et d'ASA, en utilisant Grako et Python. J'essaie de comprendre comment représenter les mots clés «délimités» dans EBNF - par exemple, le mot clé «description» doit apparaître dans une portée interface, mais il existe plusieurs options pour interface et elles sont toutes facultatives (et l'ordre peut changer entre les appareils, je crois):Comment décrire les étendues dans EBNF?

interface Vlan1435 
nameif untrust 
description the outside interface for customer X 
bridge-group 1 
security-level 0 

le plus proche, je l'ai trouvé un exemple dans une application Perl appelé Farly qui utilise le perl Parse :: module recdescent, qui semble être similaire à Grako.

De là, j'ai ce type de définition récursive:

@@eol_comments :: /!([^\n]*?)\n/ 
@@whitespace :: /[\t ]+/ 

start 
    = 
    file_input $ 
    ; 


file_input 
    = 
    {NEWLINE | asa_line} 
    ; 


asa_line 
    = 
     'names' NEWLINE 
    | interface NEWLINE 
    ; 

interface 
    = 
    'interface' string NEWLINE interface_options 
    ; 


interface_options 
    = 
    if_name | sec_level | if_addr | if_bridgegroup | NEWLINE 
    ; 


if_bridgegroup 
    = 
    'bridge-group' digit NEWLINE interface_options 
    ; 


if_name 
    = 
    'nameif' string NEWLINE interface_options 
    ; 


sec_level 
    = 
    'security-level' digit NEWLINE interface_options 
    ; 

mais il produit un AST imbriquée étrange, et il n'a pas « reset » pour détecter la seconde interface ou toute autre chose dans la configuration qui suit .

Comment ces types d'étendues sont-ils normalement définis dans EBNF? (y-a-t-il un didacticiel utile pour ce type de chose?) Mon truc de google n'a rien trouvé pour Grako ou les parseurs en général

Répondre

1

Un truc que j'utilise dans ces situations est d'utiliser la répétition même si les options peuvent n'apparaît qu'une fois:

interface_options 
    = 
    { @+:(if_name | sec_level | if_addr | if_bridgegroup) NEWLINE}* 
    ; 

Si nécessaire, vous pouvez utiliser une action sémantique pour valider que les options ne sont pas répétées.

+0

Merci! Je pense que cela, couplé avec un remplacement de classe Buffer Buffer pour repérer l'indentation (comme Python) fera l'affaire ... juste besoin de passer de la mention d'une ligne dans les docs à une chose qui fonctionne :-) – AnotherHowie

+0

Je ne ' Je pense que vous avez besoin d'un 'Buffer' pour l'indentation. Vous pouvez définir l'indentation comme un jeton dans la grammaire et utiliser une règle sémantique pour suivre la profondeur/le niveau. Rappelez-vous que vous pouvez avoir des règles "vides" juste pour activer des actions sémantiques ('unindent =();' dans votre cas). – Apalala

+0

OK, je vais essayer! – AnotherHowie